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的對數。
