1. 程式人生 > 實用技巧 >快速排序(改進的氣泡排序)

快速排序(改進的氣泡排序)

  快速排序的基本思想:從記錄中選定一個關鍵字,將待排序記錄分割成兩部分,其中一部分記錄的關鍵字小於選定關鍵字的值,另一部分記錄的關鍵字大於選定關鍵字的值;反覆對分割好的記錄進行上述操作,直到整個序列變為有序序列。

  以順序表L = {0,5,1,9,8,3}為例,length = 5,r[0]不參與排序。

  快速排序的程式碼如下所示:

 1 //交換順序表L中的記錄,使樞軸記錄放到正確位置,並返回其所在位置
 2 //交換結束後,樞軸記錄前面的記錄值小於樞軸記錄的值
 3 //後面的記錄值大於樞軸記錄的值
 4 int Partition(SqList* L, int low, int high)
 5
{ 6 int pivotkey; 7 pivotkey = L->r[low];//子表的第一個記錄當作樞軸記錄 8 9 while (low < high) 10 { 11 //從右往左,找比樞軸記錄關鍵字的值小的記錄 12 while (low < high && L->r[high] >= pivotkey) 13 high--; 14 swap(L, low, high);//將比樞軸記錄小的記錄交換到低端 15 16 //
從左往右,找比樞軸記錄關鍵字的值大的記錄 17 while (low < high && L->r[low] <= pivotkey) 18 low++; 19 swap(L, low, high);//將比樞軸記錄大的記錄交換到高階 20 } 21 22 return low;//返回樞軸所在的位置 23 }
 1 //對L->r[low,...,high]做快速排序
 2 void QSort(SqList* L, int low, int high)
 3 {
 4     int pivot;
5 if (low < high) 6 { 7 pivot = Partition(L, low, high);//樞軸的位置 8 9 QSort(L, low, pivot - 1);//對L->r[low,...,pivot - 1]遞迴排序 10 QSort(L, pivot + 1, high);//對L->r[pivot,...,high]遞迴排序 11 } 12 }

  執行Partition函式後順序表中的記錄變化如下所示:

  上述操作使樞軸記錄5到位,並返回其所在位置3,接下來,對低子表{3,1}和高子表{8,9}進行同樣的操作,最終將順序表排序為有序表。

  可以從一下幾個方面對快速排序進行優化:

  (1)優化樞軸的選取。樞軸記錄的選擇,其值居於待排序記錄的中間最好,然而,將子表的第一個記錄當作樞軸記錄,並不能保證其關鍵字的值居於待排序記錄的中間,所以衍生出了三數取中,九數取中等優化樞軸的選取的方法。我們選擇三數取中法來對快速排序進行優化,即取待排序記錄的左中右三個位置(也可以按其他方式取)的記錄中關鍵字的值居中的記錄作為樞軸記錄。

  (2)優化不必要的交換。如上所示,選定的數軸5的最終位置為3,而我們在將樞軸記錄放到該正確的位置的過程中,不斷地調整樞軸的位置,也就是不斷地進行交換,這些交換都是不必要的,我麼可以採用替換操作來代替交換操作,當找到樞軸的位置時,將樞軸值存入該位置。

  (3)優化小陣列的排序。當陣列較小時,直接插入排序的效能更好,所以可以在程式碼中加入判斷條件,當陣列較小時,選用直接插入排序;當陣列較大時,選用快速排序。

  (4)優化遞迴操作。棧的大小是有限的,且每次遞迴呼叫都會佔用一定的棧空間,函式的引數越多,佔用的棧空間越大,所以可以通過減少遞迴來提高程式的效能。我們採用尾遞迴來減少遞迴次數。

  優化的快速排序的程式碼如下所示:

 1 //交換順序表L中的記錄,使樞軸記錄放到正確位置,並返回其所在位置
 2 //交換結束後,樞軸記錄前面的記錄值小於樞軸記錄的值
 3 //後面的記錄值大於樞軸記錄的值
 4 int Partition(SqList* L, int low, int high)
 5 {
 6     int pivotkey;
 7 
 8     /********************************************************/
 9     //優化樞紐的選取
10     int mid = (low + high) / 2;
11     if (L->r[low] > L->r[high])
12         swap(L, low, high);
13     if (L->r[mid] > L->r[high])
14         swap(L, high, mid);
15     if (L->r[mid] > L->r[low])
16         swap(L, mid, low);
17     /********************************************************/
18 
19     pivotkey = L->r[low];
20 
21     /********************************************************/
22     //優化不必要的交換
23     L->r[0] = pivotkey;
24     /********************************************************/
25 
26     while (low < high)
27     {
28         while (low < high && L->r[high] >= pivotkey)
29             high--;
30 
31         /********************************************************/
32         //優化不必要的交換
33         L->r[low] = L->r[high];
34         /********************************************************/
35 
36         swap(L, low, high);
37         while (low < high && L->r[low] <= pivotkey)
38             low++;
39 
40         /********************************************************/
41         //優化不必要的交換
42         L -> r[high] = L->r[low];
43         /********************************************************/
44 
45         swap(L, low, high);
46     }
47 
48     /********************************************************/
49     //優化不必要的交換
50     L->r[low] = L->r[0];
51     /********************************************************/
52 
53     return low;
54 }
 1 //對L->r[low,...,high]做快速排序
 2 void QSort(SqList *L,int low,int high)
 3 {
 4     int pivot;
 5 
 6     /********************************************************/
 7     //優化遞迴操作
 8     while (low < high)
 9     /********************************************************/
10     {
11         pivot = Partition(L, low, high);//樞軸的位置
12 
13         QSort(L, low, pivot - 1);//對L->r[low,...,pivot - 1]遞迴排序
14 
15         /********************************************************/
16         //優化遞迴操作
17         low = pivot + 1;//尾遞迴
18         /********************************************************/
19     }
20 }

  

  執行Partition函式後順序表中的記錄變化如下所示:

  到此為止,我們介紹完了所有的排序演算法,下一次會對所有的排序演算法進行一個總結,對各種排序演算法進行比較,分析其時間複雜度以及適用情況。接下來會依次介紹查詢演算法,希望給位同儕可以多多關注,給出指導意見,多多交流!

相關連結:

氣泡排序https://www.cnblogs.com/yongjin-hou/p/13858510.html

簡單選擇排序https://www.cnblogs.com/yongjin-hou/p/13859148.html
直接插入排序https://www.cnblogs.com/yongjin-hou/p/13861458.html
希爾排序https://www.cnblogs.com/yongjin-hou/p/13866344.html

堆排序https://www.cnblogs.com/yongjin-hou/p/13873770.html

歸併排序https://www.cnblogs.com/yongjin-hou/p/13921147.html

參考書籍:程傑 著,《大話資料結構》,清華大學出版社。