快速排序演算法原理與實現(一)

來源:互聯網
上載者:User
  

快速排序是對冒泡排序的一種改進。它的基本思想是:通過一躺排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一不部分的所有資料都要小,然後再按次方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。

    假設要排序的數組是A[1]……A[N],首先任意選取一個資料(通常選用第一個資料)作為關鍵資料,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一躺快速排序。一躺快速排序的演算法是:

   1)、設定兩個變數I、J,排序開始的時候I:=1,J:=N;

   2)以第一個數組元素作為關鍵資料,賦值給X,即X:=A[1];

   3)、從J開始向前搜尋,即由後開始向前搜尋(J:=J-1),找到第一個小於X的值,兩者交換;

   4)、從I開始向後搜尋,即由前開始向後搜尋(I:=I+1),找到第一個大於X的值,兩者交換;

   5)、重複第3、4步,直到I=J;

   例如:待排序的數組A的值分別是:(初始關鍵資料X:=49)

                   A[1]     A[2]     A[3]     A[4]     A[5]      A[6]     A[7]:

                     49        38       65       97       76       13        27

進行第一次交換後:   27        38       65       97       76       13        49

                   ( 按照演算法的第三步從後面開始找

進行第二次交換後:   27        38       49       97       76       13        65

                  ( 按照演算法的第四步從前面開始找>X的值,65>49,兩者交換,此時I:=3 )

進行第三次交換後:   27        38       13       97       76       49        65

( 按照演算法的第五步將又一次執行演算法的第三步從後開始找

進行第四次交換後:   27        38       13       49       76       97        65

( 按照演算法的第四步從前面開始找大於X的值,97>49,兩者交換,此時J:=4 )

      此時再執行第三不的時候就發現I=J,從而結束一躺快速排序,那麼經過一躺快速排序之後的結果是:27        38       13       49       76       97        65,即所以大於49的數全部在49的後面,所以小於49的數全部在49的前面。

      快速排序就是遞迴調用此過程——在以49為中點分割這個資料序列,分別對前面一部分和後面一部分進行類似的快速排序,從而完成全部資料序列的快速排序,最後把此資料序列變成一個有序的序列,根據這種思想對於上述數組A的快速排序的全過程6所示:

初始狀態                        {49     38     65     97     76     13     27}   

進行一次快速排序之後劃分為      {27     38     13}     49   {76     97     65}

分別對前後兩部分進行快速排序    {13}    27    {38}

                                結束         結束    {49    65}    76    {97}

                                                    49   {65}         結束

                                                        結束

                          圖6    快速排序全過程

 

1)、設有N(假設N=10)個數,存放在S數組中;

2)、在S[1。。N]中任取一個元素作為比較基準,例如取T=S[1],起目的就是在定出T應在排序結果中的位置K,這個K的位置在:S[1。。K-1]<=S[K]<=S[K+1..N],即在S[K]以前的數都小於S[K],在S[K]以後的數都大於S[K];

3)、利用分治思想(即大化小的策略)可進一步對S[1。。K-1]和S[K+1。。N]兩組資料再進行快速排序直到分組對象只有一個資料為止。

如具體資料如下,那麼第一躺快速排序的過程是:

數組下標: 1      2      3      4      5      6      7      8      9      10

           45     36     18     53     72     30     48     93     15      36

      I                                                                   J

(1)      36     36     18     53     72     30     48     93     15      45

       

(2)      36     36     18     45     72     30     48     93     15      53

(3)      36     36     18     15     72     30     48     93     45      53

(4)      36     36     18     15     45     30     48     93     72      53

(5)      36     36     18     15     30     45     48     93     72      53

通過一躺排序將45放到應該放的位置K,這裡K=6,那麼再對S[1。。5]和S[6。。10]分別進行快速排序。

 

一般來說,冒泡法是程式員最先接觸的排序方法,它的優點是原理簡單,編程實現容易,但它的缺點就是--程式的大忌--速度太慢。下面我介紹一個理解上簡單但編程實現上不是太容易的排序方法,我不知道它是不是現有排序方法中最快的,但它是我見過的最快的。排序同樣的數組,它所需的時間只有冒泡法的 4% 左右。我暫時稱它為“快速排序法”。

     “快速排序法”使用的是遞迴原理,下面我結合一個例子來說明“快速排序法”的原理。首先給出一個數組{53,12,98,63,18,72,80,46, 32,21},先找到第一個數--53,把它作為中間值,也就是說,要把53放在一個位置,使得它左邊的值比它小,右邊的值比它大。{21,12,32, 46,18,53,80,72,63,98},這樣一個數組的排序就變成了兩個小數組的排序--53左邊的數組和53右邊的數組,而這兩個數組繼續用同樣的方式繼續下去,一直到順序完全正確。

     我這樣講你們是不是很胡塗,不要緊,我下面給出實現的兩個函數:

/*
n就是需要排序的數組,left和right是你需要排序的左界和右界,
如果要排序上面那個數組,那麼left和right分別是0和9
*/

void quicksort(int n[], int left,int right)
{
int dp;
if (left<right) {

     /*
     這就是下面要講到的函數,按照上面所說的,就是把所有小於53的數放
     到它的左邊,大的放在右邊,然後返回53在整理過的數組中的位置。
     */
     dp=partition(n,left,right);

     quicksort(n,left,dp-1);

     quicksort(n,dp+1,right); //這兩個就是遞迴調用,分別整理53左邊的數組和右邊的數組
}
}

     我們上面提到先定位第一個數,然後整理這個數組,把比這個數小的放到它的左邊,大的放右邊,然後

返回這中間值的位置,下面這函數就是做這個的。
int partition(int n[],int left,int right)
{
int lo,hi,pivot,t;

pivot=n[left];
lo=left-1;
hi=right+1;

while(lo+1!=hi) {
     if(n[lo+1]<=pivot)
       lo++;
     else if(n[hi-1]>pivot)
       hi--;
     else {
       t=n[lo+1];
       n[++lo]=n[hi-1];
       n[--hi]=t;
     }
}

n[left]=n[lo];
n[lo]=pivot;
return lo;
}

     這段程式並不難,應該很好看懂,我把過程大致講一下,首先你的腦子裡先浮現一個數組和三個指標,第一個指標稱為p指標,在整個過程結束之前它牢牢的指向第一個數,第二個指標和第三個指標分別為lo指標和hi指標,分別指向最左邊的值和最右邊的值。lo指標和hi指標從兩邊同時向中間逼近,在逼近的過程中不停的與p指標的值比較,如果lo指標的值比p指標的值小,lo++,還小還++,再小再++,直到碰到一個大於p指標的值,這時視線轉移到hi指標,如果 hi指標的值比p指標的值大,hi--,還大還--,再大再--,直到碰到一個小於p指標的值。這時就把lo指標的值和hi指標的值做一個調換。持續這過程直到兩個指標碰面,這時把p指標的值和碰面的值做一個調換,然後返回p指標新的位置。

  1. #include<iostream>
  2. using namespace std;
  3. int a[200001],n;
  4. void swap(int &a,int &b){
  5. int tmp = a;
  6. a = b;
  7. b = tmp;
  8. }
  9. int partition(int p,int r){
  10. int rnd = rand()%(r-p+1)+p;
  11. swap(a[rnd],a[r]);
  12. int pvt = r, i = p-1;
  13. for(int j = i+1;j<r;j++)
  14. if(a[j]<a[pvt])
  15. swap(a[j],a[++i]);
  16. swap(a[++i],a[pvt]);
  17. return i;
  18. }
  19. void qsort(int p,int r){
  20. if(p<r){
  21. int q = partition(p,r);
  22. qsort(p,q-1);
  23. qsort(q+1,r);
  24. }
  25. }
  26. int main(){
  27. cin>>n;
  28. for(int i=0;i<n;i++)
  29. cin>>a[i];
  30. qsort(0,n-1);
  31. for(int i=0;i<n;i++)
  32. cout<<a[i];
  33. return 0;
  34. }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.