快速排序的優化


  在我的上一篇博客中(https://www.cnblogs.com/algorithm-process/p/11963856.html),我們提到了快速排序划分的三鍾方法,在快速排序中,我們希望對序列進行划分時,能將一個序列進行兩等分,但是我們在使用時始終選取第一個元素為基准值,這樣就會導致在一些情況(比如是降序排列的序列)下,無法將序列進行等分或是近似等分。如果我們每次選擇基准值是一個中間值是不是能盡可能的將待排序的序列做到一個趨近於等分的情況呢?接下來就是由這種思想而提出的優化方法。

 三點中值法

  思想:在左邊界p,右邊界r和中間下標mid所代表的元素之間選擇一個作為基准點,選擇方法為找到這三個值中中間那個作為基准點。

  代碼如下:

 1 int partition(int a[],int p,int r){
 2     //選取一個基准點 
 3     int midIndex= p+((r-p)>>1);//中間下標
 4     int midValue=-1;//中間值下標
 5     if(a[p]<=a[midIndex]&&a[p]>=a[r]) midValue=p;
 6     else if(a[r]<=a[midIndex]&&a[r]>=a[p]) midValue=r;
 7     else midValue=midIndex;
 8     swap(a[midValue],a[p]);
 9     
10     int x=a[l];//基准點
11     int l=p+1,q=r;
12     while(l<=q){
13         while(a[l]<=x&&l<=q) ++l;
14         while(a[q]>x&&l<=q) --q;
15         if(l<=q) swap(a[l],a[q]);
16      }
17      swap(a[p],a[q]);
18      return q;
19 }

   在這三個點中找中間值作為基准點在某些情況下也並不能代表整個序列的中間值,為了能得到一個真正的中間值,我們在此基礎上又提出了進一步求中間值的方法。

 絕對中值法

  思想:將一個數組分成每五個元素一組,若最后一組元素不足五個,也作為一組。然后使用一個數組來存儲每個划分中的中間值,得到每個划分的中間值后,取這個數組的中間值,即為所求的中間值。

  得到中間值的代碼如下:

 1 void insertsort(int a[],int p,int q){//插入排序 
 2     int temp;
 3     for(int i=p;i<=q;i++){
 4         if(a[i]<a[i-1]){
 5             temp=a[i];
 6             for(int j=i;j>=0;j--){
 7                 if(j>0&&a[j-1]>temp) a[j]=a[j-1];
 8                 else {
 9                     a[j]=temp;
10                     break;
11                 }
12             }
13         }
14     }
15 }
16 int getmid(int a[],int p,int r){
17     int length=r-p+1;
18     int grouplength=(length%5==0)?(length/5):(length/5+1);//每五個元素一組,得到划分的個數 
19     int *medians=new int[grouplength];//定義存儲中間值的數組
20     int midIndex=0;
21     for(int i=0;i<grouplength;i++){
22         if(i==grouplength-1){//最后一組時 ,需要單獨處理,因為這組中元素個數小於5個 
23             insertsort(a,p+j*5,r);//調用插入排序 
24             medians[midIndex++]=a[(p+j*5+r)/2];//存入數組 
25         }else {
26             insertsort(a,p+j*5,p+j*5+4);
27             medians[midIndex++]=a[(p+j*5+2)];
28         }
29     } 
30     insertsort(mediams,0,grouplength-1);
31     return medians[grouplength/2];
32 } 

 

 

   這種方法得到中間值的時間復雜度為O(n),但是通常我們並不使用它,更多的是使用三點中值法。

 當序列中元素較少時,使用插入排序

  思想:雖說插入排序的時間復雜度為O(n2),但是實際上是:n(n-1)/2。快速排序的時間復雜度為O(nlogn),實際上是:n(logn+1)。經過計算后發現當n<=8時,插入排序所消耗的時間是少於快速排序的。

  經過優化后的代碼是:

  

 1 quicksort(int a[],int l,int r){//快排遞歸形式 
 2     if(l<r){
 3         if((r-l+1)<=8) insertsort(a,l,r);//調用插入排序
 4         else{
 5             int q=partition(a,l,r);//找到中間數,不一定是中位數 
 6             quicksort(a,l,q-1);
 7             quicksort(a,q+1,r);            
 8         } 
 9     }
10 }

 

 

 上述就是比較常用的三種優化方法了。


免責聲明!

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



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