C語言:快速排序


快速排序是排序算法中,平均時間復雜度為O(n*log n)的一種算法,其實現需要先解決這樣的一個問題,對一個序列A[1],A[2],A[3] .......A[N],調整序列中元素的位置,使得A[1](原序列中的第一個元素,下同)的左側所有元素都不超過A[1],右側所有元素都大於A[1],例如對序列{5,3,9,6,4,1}來說,調整后變為{3,1,4,5,9,6}這樣就讓A[1] =5 ,左側的所有元素,不超過它,右側的所有元素都大於它。

排序思想

1.快排是對冒泡排序的一種改進,在快速排序中,元素的比較和移動是從兩端向中間進行的,關鍵碼較大的元素一次就能從前面移動到后面,關鍵碼較小的元素一次就能從后面移動到前面,元素移動距離的較遠,從而減少了總的比較次數和移動次數

2.快速排序是基於分治法設計的,其分治策略是: 
①、划分:選定一個元素作為軸值,以軸值為基准將整個序列划分為兩個子序列。軸值的位置在划分的過程中確定,並且前一個子序列的元素均小於或者等於軸值,后一個子序列的元素大於或者等於軸值

②、求解子問題:分別對划分后的每一個子序列遞歸處理 
③、合並:由於對子序列的排序是就地進行的,所以合並並不需要執行任何操作

排序方法

1.選擇軸值,一般是選取第一個元素的關鍵碼。有一個快排的最壞情況就是如果待排序元素是正序或者逆序,就會將除軸值以外的元素分到軸值的一邊。 
2.划分 
①、設置划分區間:i=first,j=end 
②、執行右側掃描,直到r[j]小於軸值,將r[j]與r[i]交換,i++ 
③、執行左側掃描,直到r[i]大於軸值,將r[i]與r[j]交換,j– 
④、重復二到三直到i=j,確定看軸值的所在位置,返回該位置

 

初始鍵值序列   23 12 35 6 19 50 28

一次划分后    [19 13 6]    23  [35 50 28]

分別進行快速排序 [6 13]  19    [28]  35   [50]

          6  [13]             35 

             13    28        50

最終結果                6  13  19  23  28  35  50

 

 1 //對區間[left,right]進行划分
 2 int Partition(int A[],int left, int right)
 3 {
 4     int temp =A[left]; //存放到臨時變量temp
 5 
 6     while(left < right) //只要left與right不相遇
 7     {
 8         while(left < right && A[right] > temp) right--;//反復左移
 9         A[left] = A[right];
10 
11         while(left < right && A[left] <= temp) left++;//反復右移
12         A[right] = A[left];
13     }
14 
15     A[left] = temp;    //把temp放到right與left相遇的地方
16     return left;    //返回相遇下標
17 }

快速排序算法當序列中元素的排列比較隨機時效率高,但是當序列中元素接近有序時,會達到最壞時間復雜度O(n^2),產生這種情況的主要原因在於主元沒有把當前區間划分為兩個長度接近的子區間。有什么辦法能解決這個問題呢?那就是隨機選取主元,這樣雖然算法的最壞時間復雜度仍然是O(n^2)(例如,總是選擇A[left]為主元),但是對於任意輸入數據的期望時間復雜度都能達到O(n*log n),也就是說,不存在一組特定的數據能使這個算法出現最壞情況。

 

 1 int randPartition(int A[],int left, int right)
 2 {
 3     //生成[left,right]內的隨機主元
 4     int p = (round(1.0*rand()/RAND_MAX)*(right-left)+left);
 5     swap(A[p],A[left]);
 6     int temp =A[left];
 7     while(left < right)
 8     {
 9         while(left < right && A[right] > temp) right--;//反復左移
10         A[left] = A[right];
11         while(left < right && A[left] <= temp) left++;//反復右移
12         A[right] = A[left];
13     }
14     A[left] = temp;
15     return left;
16 }

快速排序的遞歸實現如下:

 

 1 //快速排序,left與right初值為序列下標(例如 1 與 n)
 2 void quicksort(int A[], int left, int right)
 3 {
 4     if(left < right) // 當前區間的長度超過1
 5     {
 6         //將[left,right]按A[right]一分為2
 7         int pos = randPartition(A,left,right);
 8         quicksort(A, left, pos-1);  //對左子區間遞歸進行快速排序
 9         quicksort(A, pos+1, right); //對右子區間遞歸進行快速排序
10     }
11 }

 


免責聲明!

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



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