PS:什么是遞歸、二分查找、歸並排序。
遞歸排序大家都不陌生,遞歸簡單的說就是自己在沒有達到目的的同時在此調用本身,把一個大問題層層轉化為和原問題相似的小問題解決,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。
二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。但是,折半查找要求線性表必須采用順序存儲結構,而且表中元素按關鍵字有序排列。
歸並排序(MERGE-SORT)是建立在歸並操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為二路歸並。
如果想了解更多可以去百度百科查閱即可。下面是簡單例子
1、二分查找法
思路
二分法就是把一個數組折半查找,再折半直到找到數據位置,或者無數據位置。比如說1-100,你選的值是23,那么范圍寫法就是(索引寫法類似)
第一次折半是1-50,51-100,經過查找23<50,是在1-50里。
第二次是1-25,26-50,經過查找23<25,是在1-25里。
..........
使用條件
- 必須是有序數據
- 升序和降序start角標和end角標寫法相反
/** * 方法描述:二分查找方法 * **/ public static int twoQueryMethod(int[] data,int query){ int start=0; //開始角標 int end=data.length-1; //結束角標 int moddle; while(true){ moddle=(end+start)/2; if(data[moddle] == query){ return moddle; } //起始角標 > 最后角標 沒有找到 else if(start > end){ return data.length; } else{ //中間值大於查找值 if(data[moddle] > query){ end = moddle-1; }else{ start = moddle + 1; } } } }
上面是用平常的while循環寫的,下面用遞歸的寫法。
2:遞歸---二分查找法
使用遞歸可以取消while的循環使用
/** * 遞歸取代while循環 * * **/ //降序查找 public static int diGuiMethod(int[] data,int search,int start,int end){ //獲取中間值角標 int moddle=(start+end)/2; if(data[moddle] == search){ return moddle; }else if(start > end){ return data.length; }else{ //下面是降序 if(data[moddle]< search){ return diGuiMethod(data,search,start,moddle-1); }else{ return diGuiMethod(data, search, moddle+1, end); } } } //升序查找 public static int binarySearch(int[] arr, int data, int beginIndex, int endIndex) { int midIndex = (beginIndex + endIndex) / 2; if (data < arr[beginIndex] || data > arr[endIndex] || beginIndex > endIndex) { return -1; } if (data < arr[midIndex]) { return binarySearch(arr, data, beginIndex, midIndex - 1); } else if (data > arr[midIndex]) { return binarySearch(arr, data, midIndex + 1, endIndex); } else { return midIndex; } }
效率
普通二分查找法和遞歸二分查找都是 O(logN) 但是資料顯示 遞歸二分查找簡介但稍微慢一點。
擴展--分治算法
分治算法的基本思想是將一個規模為N的問題分解為K個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。求出子問題的解,就可得到原問題的解。即一種分目標完成程序算法,簡單問題可用二分法完成。
分治算法--基本思想
當我們求解某些問題時,由於這些問題要處理的數據相當多,或求解過程相當復雜,使得直接求解法在時間上相當長,或者根本無法直接求出。對於這類問題,我們往往先把它分解成幾個子問題,找到求出這幾個子問題的解法后,再找到合適的方法,把它們組合成求整個問題的解法。如果這些子問題還較大,難以解決,可以再把它們分成幾個更小的子問題,以此類推,直至可以直接求出解為止。這就是分治策略的基本思想。
3:歸並排序
歸並排序(MERGE-SORT)是建立在歸並操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為二路歸並。
歸並排序的條件、使用優點
- 通過兩個不同的有序數組,互相比較按照比較大小排序
- 把一個無序的數組分成N個數據,每個數據本身比較一次,之后再和下一個數組比較並合並,以此類推。
3.1:兩個A,B不同的(有序)數組歸並成一個C數組,結果C還是有序的。
public static void mergeTwo(int[] arr1,int[] arr2,int[] mergeArr){ int aIndex=0,bIndex=0,mIndex=0; //兩個數組都有數據時 while(aIndex < arr1.length && bIndex < arr2.length){ if(arr1[aIndex]<arr2[bIndex]){ mergeArr[mIndex++] = arr1[aIndex++]; }else{ mergeArr[mIndex++] = arr2[bIndex++]; } } //如果兩個數組長度相等,則下方方法就不會執行,如果A長度大於B,則會走第一個while。 //兩個數組其中一個無數據時 while(aIndex < arr1.length){ mergeArr[mIndex++] = arr1[aIndex++]; } while(bIndex < arr2.length){ mergeArr[mIndex++]=arr2[bIndex++]; } //遍歷結果 for(int i=0;i<mergeArr.length;i++){ System.out.println(mergeArr[i]); } }
使用
//main方法中使用 int[] arr1={12,14,15,16}; int[] arr2={8,22,56,90,100}; int [] merge=new int[9]; mergeTwo(arr1, arr2, merge);
3.2:歸並算法--排序一個無需數組
/** * 一個數組內部進行排序 * * **/ public static void mergeOne(int arr[],int startInt,int stopInt,int[] cArr){ //如果范圍是1則直接返回。 if(stopInt==startInt){ return; } else{ int middle=(startInt+stopInt)/2; //開始把數組分開---二分法 mergeOne(arr, startInt, middle,cArr); mergeOne(arr, middle+1, stopInt,cArr); mergeTwoSort(arr,startInt,middle,stopInt,cArr); } } public static void mergeTwoSort(int arr[],int start,int mid,int end,int[] cArr){ int left=start;//左序列開始角標 int right=mid+1;//右序列開始角標 int cIndex=0;//臨時數組 //當兩邊都有值時執行 while(left <= mid&& end>=right){ //比較兩個數組的元素大小,如:A:left=0開始到3,長度為4,B:right=4開始,長度為4, if(arr[left]<arr[right]) { cArr[cIndex++]=arr[left++]; }else{ cArr[cIndex++]=arr[right++]; } } //當右邊數組無元素時執行 while(left<=mid){ cArr[cIndex++]=arr[left++]; } //當左邊數組無元素時執行 while(right<=end){ cArr[cIndex++]=arr[right++]; } //將臨時數組全部添加進原數組 cIndex=0;//指針修改為0 while(start<=end){ arr[start++]=cArr[cIndex++]; } }
使用
//mian方法使用 //一個數組內部排序 int[] arr3={12,4,34,5,6,45,9}; int[] cArr=new int[7]; mergeOne(arr3, 0, 6, cArr); System.out.println("一個數組內部排序"); for(int i=0;i<cArr.length;i++){ System.out.println(cArr[i]);
歸並效率
O(log2\N)以2為底N的對數。