1. 程式人生 > >006.交換排序—快速排序(Quick Sort)

006.交換排序—快速排序(Quick Sort)

基本思想:

1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素,

2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。

3)此時基準元素在其排好序後的正確位置

4)然後分別對這兩部分記錄用同樣的方法繼續進行排序,直到整個序列有序。

快速排序的示例:

(a)一趟排序的過程:

(b)排序的全過程


演算法的實現:

 遞迴實現:

  1. void print(int a[], int n){  
  2.     for(int j= 0; j<n; j++){  
  3.         cout<<a[j] <<"  ";  
  4.     }  
  5.     cout<<endl;  
  6. }  
  7. void swap(int *a, int *b)  
  8. {  
  9.     int tmp = *a;  
  10.     *a = *b;  
  11.     *b = tmp;  
  12. }  
  13. int partition(int a[], int low, int high)  
  14. {  
  15.     int privotKey = a[low];                             //基準元素
  16.     while(low < high){                                   //從表的兩端交替地向中間掃描
  17.         while(low < high  && a[high] >= privotKey) --high;  
    //從high 所指位置向前搜尋,至多到low+1 位置。將比基準元素小的交換到低端
  18.         swap(&a[low], &a[high]);  
  19.         while(low < high  && a[low] <= privotKey ) ++low;  
  20.         swap(&a[low], &a[high]);  
  21.     }  
  22.     print(a,10);  
  23.     return low;  
  24. }  
  25. void quickSort(int a[], int low, int high){  
  26.     if(low < high){  
  27.         int privotLoc = partition(a,  low,  high);  //將表一分為二
  28.         quickSort(a,  low,  privotLoc -1);          //遞迴對低子表遞迴排序
  29.         quickSort(a,   privotLoc + 1, high);        //遞迴對高子表遞迴排序
  30.     }  
  31. }  
  32. int main(){  
  33.     int a[10] = {3,1,5,7,2,4,9,6,10,8};  
  34.     cout<<"初始值:";  
  35.     print(a,10);  
  36.     quickSort(a,0,9);  
  37.     cout<<"結果:";  
  38.     print(a,10);  
  39. }  

分析:

快速排序是通常被認為在同數量級(O(nlog2n))的排序方法中平均效能最好的。但若初始序列按關鍵碼有序或基本有序時,快排序反而蛻化為氣泡排序。為改進之,通常以“三者取中法”來選取基準記錄,即將排序區間的兩個端點與中點三個記錄關鍵碼居中的調整為支點記錄。快速排序是一個不穩定的排序方法。

 
快速排序的改進

在本改進演算法中,只對長度大於k的子序列遞迴呼叫快速排序,讓原序列基本有序,然後再對整個基本有序序列用插入排序演算法排序。實踐證明,改進後的演算法時間複雜度有所降低,且當k取值為 8 左右時,改進演算法的效能最佳。演算法思想如下

  1. void print(int a[], int n){  
  2.     for(int j= 0; j<n; j++){  
  3.         cout<<a[j] <<"  ";  
  4.     }  
  5.     cout<<endl;  
  6. }  
  7. void swap(int *a, int *b)  
  8. {  
  9.     int tmp = *a;  
  10.     *a = *b;  
  11.     *b = tmp;  
  12. }  
  13. int partition(int a[], int low, int high)  
  14. {  
  15.     int privotKey = a[low];                 //基準元素
  16.     while(low < high){                   //從表的兩端交替地向中間掃描
  17.         while(low < high  && a[high] >= privotKey) --high; //從high 所指位置向前搜尋,至多到low+1 位置。將比基準元素小的交換到低端
  18.         swap(&a[low], &a[high]);  
  19.         while(low < high  && a[low] <= privotKey ) ++low;  
  20.         swap(&a[low], &a[high]);  
  21.     }  
  22.     print(a,10);  
  23.     return low;  
  24. }  
  25. void qsort_improve(int r[ ],int low,int high, int k){  
  26.     if( high -low > k ) { //長度大於k時遞迴, k為指定的數
  27.         int pivot = partition(r, low, high); // 呼叫的Partition演算法保持不變
  28.         qsort_improve(r, low, pivot - 1,k);  
  29.         qsort_improve(r, pivot + 1, high,k);  
  30.     }   
  31. }   
  32. void quickSort(int r[], int n, int k){  
  33.     qsort_improve(r,0,n,k);//先呼叫改進演算法Qsort使之基本有序
  34.     //再用插入排序對基本有序序列排序
  35.     for(int i=1; i<=n;i ++){  
  36.         int tmp = r[i];   
  37.         int j=i-1;  
  38.         while(tmp < r[j]){  
  39.             r[j+1]=r[j]; j=j-1;   
  40.         }  
  41.         r[j+1] = tmp;  
  42.     }   
  43. }   
  44. int main(){  
  45.     int a[10] = {3,1,5,7,2,4,9,6,10,8};  
  46.     cout<<"初始值:";  
  47.     print(a,10);  
  48.     quickSort(a,9,4);  
  49.     cout<<"結果:";  
  50.     print(a,10);  
  51. }