遞歸排序算法


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);      //對基數后的子序列進行遞歸排序
    }
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM