1.思想:
遞歸調用是用相同的方法去解決更小的問題,直到問題規模小於或等於某個邊界條件時,不再進行遞歸(遞歸的出口),而是直接處理,然后不斷向下執行函數返回結果。
2.分治法
1.當問題小到一定規模時,可以直接求解;
2.當問題規模較大時,可以分解為若干個相互獨立的子問題,這些子問題與原問題具有相同的特征。若不能直接解決,則可分別遞歸求解;
3.原問題的解是子問題的解的組合。
3.折半查找
遞歸實現如下:
int BinSearch(int *arr,int key,int low,int high){
int mid = (low + high)/2; //取中
if(low>high) return -1; //找不到目標關鍵字,也就是遞歸程序的出口 if(key = mid) //找到返回,出口 return mid; else if(key<mid) return BinSearch(arr,key,low,mid-1); //遞歸調用 else return BinSearch(arr,key,mid+1,high); }
4.歸並排序
要點:采用分治法的策略,將已有的有序子序列合並為完全有序的序列,首先要讓子序列有序,然后再使子序列間有序,最后等到完全有序的序列。
思想:將待排序序列R[0,...n-1]分為n個長度為1的子序列,講相鄰的子序列進行歸並,得到n/2個長度為2的有序表;將這些有序序列再次歸並,得到n/4個長度為4的有序序列;如此反復進行下去,最后得到一個長度為n的 有序序列。
首先要做兩步:
1.分解 ——將序列每次折半划分。
2.合並 ——將划分后的序列段兩兩合並后排序。
那么現在我們就要解決兩個問題,怎么分解和合並?
分析:
在某趟歸並中,設各子文件長度為length(最后一個子文件的長度可能小於length),則歸並前R[1..n]中共有n/length個有序的子文件:R[1..length],R[length+1..2length],…。
注意:
調用歸並操作將相鄰的一對子文件進行歸並時,必須對子文件的個數可能是奇數、以及最后一個子文件的長度小於length這兩種特殊情況進行特殊處理:
① 若子文件個數為奇數,則最后一個子文件無須和其它子文件歸並(即本趟輪空);
② 若子文件個數為偶數,則要注意最后一對子文件中后一子文件的區間上界是n。
一趟歸並代碼:
void Merge(int * a,int low,int mid,int high) { int i=low,j=mid+1,p=0; int * r=new int[high-low+1]; while(i<=mid && j<=high) { r[p++]=(a[i]<=a[j])?a[i++]:a[j++]; } while(i<=mid) r[p++]=a[i++]; while(j<=high) r[p++]=a[j++]; for(p=0,i=low;i<=high;p++,i++) a[i]=r[p]; delete [] r; }
void MergePass(int *a,int n,int length) { int i=0; for(;i+2*length<n-1;i+=2*length) { Merge(a,i,i+length-1,i+2*length-1); } if(i+length<=n-1) Merge(a,i,i+length-1,n-1);//尚有兩個子文件,其中后一個長度小於length,歸並最后兩個子文件 //注意:若i≤n-1且i+length-1≥n-1時,則剩余一個子文件輪空,無須歸並 }
二路歸並代碼:
//自底向上 void MergeSort(int *a,int n) { for(int length=1;length<n;length*=2) MergePass(a,n,length); }
5.快速排序
基本思想:首先從待排序中選定一個基數,通過關鍵字和基數的比較將待排序列划分為兩個子序列,其中在基數前的都不大於基數;我們發現每次都是把基數歸位。
划分算法:
int Partition(int arr[],int low,int high){ int temp =arr[low]; while(low<high){ //low和high從待排序列兩端向中間移動 while(low<high&&arr[high]>=temp) --high; arr[low] = arr[high]; //將 比temp小的移到低端 while(low<high&&arr[low]<=temp) --low; arr[high] = arr[low]; //將比temp大的移到高端 } arr[low] = temp; return low; }
遞歸核心代碼:
void QSort(int arr[],int s,int t){ int pirvotloc; if(s<t){ pirvotloc = Partition(arr,s,t); //進行划分並返回基數位置 QSort(arr,s,pirvotloc-1); //對基數前的子序列進行遞歸排序 QSort(arr,pirvotlov+1,t); //對基數后的子序列進行遞歸排序 } }