快速排序

  快速排序爲何被稱之爲快速排序呢?從字面意思上來看確定是由於它比較快啦。固然實際上也是這樣,相比於其餘的排序算法,它的平均的時間複雜度爲O(nlogn),這能夠說是很快的一種排序算法了。固然在某些狀況下,也會出現比其餘排序算法慢的情形,因此沒有什麼最好的排序算法,只有最合適的排序算法。因此在日常應用的時候要根據實際狀況來選擇合適的排序算法。ios

  拿爲何快排比較快呢?由於它每次進行了劃分,選擇一個基準值後,將這個待排序序列分紅了小於基準值的一半和大於基準值的一半,而後繼續進行相同的操做,知道最後的一半隻剩下一個元素。算法

  對快速排序算法的描述:

    1.分解:數組A[p...r]被劃分爲連個子數組A[p...q-1]和A[q+1...r],使得A[p...q-1]中全部的數都比A[q]小,A[q+1...r]中全部的數都比A[q]大;數組

    2.解決:經過遞歸調用快速排序,對子數組A[p...q-1]和A[q+1...r]進行排序;測試

    3.合併:由於數組原址排序,所進行完以後數組A[p...r]已經有序。ui

  代碼以下:spa

1 quicksort(int a[],int l,int r){//快排遞歸形式 
2     if(l<r){
3         int q=partition(a,l,r);//找到中間數,不必定是中位數 
4         quicksort(a,l,q-1);
5         quicksort(a,q+1,r);
6     }
7 }

   因此接下就是如何解決劃分(partition)的問題了。有三種方法能夠來解決劃分的問題:一遍單向掃描法,雙向掃描法和三分法,接下來咱們就來好好看看這三種方法。指針

 一遍單向掃描法

  思路:首先找到一個基準值p,使用兩個指針(sp,bigger)將待排序的數組分紅三個部分,sp左邊的表示所有小於基準值的,bigger右邊的部分表示所有大於基準值的,sp和bigger之間的部分爲待排序的部分。code

  當sp元素小於p時,交換sp和bigger的元素,而後bigger--。blog

  代碼以下:排序

 1 int partition(int a[],int l,int r){
 2     int x=a[l];//基準值
 3     int sp=l+1,bigger=r;//選定兩個指針
 4     while(sp<=bigger){
 5         if(a[sp]<=x) ++sp;//當掃面元素小於基準值時,右移掃描指針 
 6         else {//當掃描元素大於基準值時,兩個指針的元素交換,而後左移右側指針 
 7             swap(a[sp],a[bigger]);
 8             --bigger;
 9         }
10     } 
11     swap(a[l],a[bigger]);//最後基準值與bigger指針元素交換,獲得 
12     return bigger;//獲得中間值 
13 }

 

  一遍單向掃描只能從一個放向走到底,這樣看起來是否是也很慢呢?若是咱們讓這兩個指針進行相對的移動是否是更快了!!這就是咱們接下來要介紹的雙向掃描法。

 雙向掃描法

  思路:和上面的一遍單向掃描法同樣也是設置兩個指針分別爲左指針sp,右指針bigger,最終獲得的結果也是sp左邊的元素都比p小,bigger右邊的元素都比p大。那和一遍單向掃描法的區別在於sp和bigger指針同時相向移動,當sp元素大於p且bigger元素大於p時,兩個指針所指的元素交換位置,而後繼續移動指針,直到到達邊界條件。

  

    代碼以下:

 1 int partition(int a[],int l,int r){
 2     int x=a[l];//基準值
 3     int p=l+1,q=r;
 4     while(p<=q){
 5         //記住得加上邊界條件,由於在移動指針的過程當中可能會越界  
 6         while(a[p]<=x&&p<=q) ++p;//sp元素小於p則右移
 7         while(a[q]>x&&p<=q) --q;//bigger元素大於p則左移
 8         if(p<=q) swap(a[p],a[q]);//交換兩指針元素
 9      }
10        //此時bigger在sp左邊且bigger所指元素是小於p的
11      swap(a[l],a[q]);//最後還得與基準值交換
12      return q;
13 }

 

  最後還有一種較爲特殊的狀況,當待排序序列中的重複元素較多時,咱們可使用一個equal指針來指向與基準值相等的元素,而後返回相等序列的頭部和尾部。接下來咱們就介紹下這個方法。

 三分法

  思路:1.選定基準值,
             2.使用三個指針,一個掃描指針sp,一個右指針bigger,一個相等指針equel
             3.當sp小於基準值時,equel元素與sp元素交換,而後equel,sp右移,
                當sp等於基準值時,sp右移
                當sp元素大於基準值時,sp元素與bigger元素交換,bigger左移
             4.最後equel-1元素與基準值交換,返回equel-1和bigger

   

    代碼以下:

 1 #include<iostream>
 2 #include<algorithm> 
 3 using namespace std;
 4 
 5 struct equal {//使用一個結構體來存儲中間相等區間的左邊界和右邊界 
 6     int right;
 7     int left;
 8 }equal1;
 9 
10 void  partition(int a[],int l,int r){
11     int x=a[l];
12     int sp=l+1,e=l+1,bigger=r;
13     while(sp<=bigger){
14         if(a[sp]<x) {
15             swap(a[e],a[sp]);
16             ++e;
17             ++sp;
18         }
19         else if(a[sp]==x) ++sp;
20         else {
21             swap(a[bigger],a[sp]);
22             --bigger;
23         }
24     }
25     swap(a[l],a[e-1]);
26     equal1.right=bigger;
27     equal1.left=e-1;
28 }
29 
30 quicksort(int a[],int l,int r){//快排遞歸形式 
31     if(l<r){
32         partition(a,l,r);//找到中間數,不必定是中位數 
33         quicksort(a,l,equal1.left-1);
34         quicksort(a,equal1.right+1,r);
35     }
36 }
37 int main(){
38     int a[10]={4,6,4,2,8,0,1,4,5,4};//測試數據
39     quicksort(a,0,9);
40     for(int i=0;i<10;i++) cout<<a[i]<<" ";
41     cout<<endl; 
42     return 0;
43 } 

  以上就是快排的三種基本方法,能夠根據實際狀況來選擇使用哪中劃分方法。歡迎你們指正哦~,若是喜歡的話,點個關注唄(●'◡'●)。

相關文章
相關標籤/搜索