資料結構與演算法 十個排序演算法之六 快速排序

2022-06-03 16:00:15 字數 2995 閱讀 3815

快速排序是由 東尼·霍爾 所發展的一種排序演算法。在平均狀況下,排序 n 個專案要 ο(n log n) 次比較。在最壞狀況下則需要 ο(n2) 次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他 ο(n log n) 演算法更快,因為它的內部迴圈(inner loop)可以在大部分的架構上很有效率地被實現出來。

快速排序使用分治法(divide and conquer)策略來把乙個序列(list)分為兩個子串行(sub-lists)。快速排序又是一種分而治之思想在排序演算法上的典型應用。本質上來看,快速排序應該算是在氣泡排序基礎上的遞迴分治法。

快速排序「人如其名」!聽這名字你就知道它有多快,效率多麼高效!它是處理大資料最快的排序演算法之一。雖然 worst case 的時間複雜度達到 o(n²),但是在大多數情況下都比平均時間複雜度為 o(n log n) 的排序演算法表現要更好。

快速排序的最壞運**況是 o(n²),比如說順序數列的快排。但它的平攤期望時間是 o(n log n),且 o(n log n) 記號中隱含的常數因子很小,比複雜度穩定等於 o(n log n) 的歸併排序要小很多。所以對絕大多數順序性較弱的隨機數列而言,快速排序總是優於歸併排序。

對於下面待排序的陣列:

163161

158165

171170

163159

162第一步:先選擇第乙個數 163 為基準數,以 163 為基準將小於它的數排在它前面,大於等於它 的數排在其後,結果如下:

162161

158159

163170

163171

165具體排列資料的步驟

1. 確定 163 為基準數後,先把 163 從陣列中取出來

161158

165171

170163

159162

2. 然後從最右端開始,查詢小於基準數 163 的數,找到 162,將其移至空出來的元素中,

162161

158165

171170

163159

3. 接下來,從最左邊未處理的元素中從左至右掃瞄比基數 163 大的數,將其移動至右側空出 來的元素中

162161

158171

170163

159165

4. 接下來,繼續從最右邊未處理的元素中從右至左掃瞄比基數 163 小的數,將其移動至左側 空出來的元素中

162161

158159

171170

163165

接下來再重複執行步驟 3,171 執行右移

162161

158159

170163

171165

重複執行步驟 4,此時右邊的值已經均大於基數,左邊的值均已小於基數

162161

158159

170163

171165

接下來我們將基數儲存回黃色空格中

162161

158159

163170

163171

165二步:採用分治法分別對基數左邊和右邊的部分運用第一步中的方法進行遞迴操作,直到整個 陣列變得有序,以左邊的陣列為例:

162161

158159

選擇 162 為基數,挪移得到結果如下:

159161

158162

以 162 為界,把陣列分成兩個部分,此時,基數右側已經沒有資料,所以,接下來只要繼續 對左側的陣列分治處理即可,選擇 159 為基數,再次挪移得到結果如下:

158159

161總結:

從數列中挑出乙個元素,稱為 "基準"(pivot);

重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;

遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序;

**實現:

1 #include 2 #include 3

4int partition(int arr, int low, int

high)518

19if(i < j) //

右邊已經找到小於基數的數

2023

24while(i < j && arr[i] < base)25

2829

if( i < j) //

左邊已經找到大於基數的數

3033

}34 arr[i] = base;35

}36return

i;37}38

39void quicksort(int *arr, int low, int high) //

實現快速排序

4047}48

49int main(void)50

;52int len = sizeof(arr)/sizeof(arr[0

]);53

54/*

int index = partition(arr, 0, len-1);

55printf("分割槽完畢, 基數下標: %d\n", index);

56*/

5758 quicksort(arr, 0, len-1

);59

60 printf("

執行快速排序後的結果:\n");

6162

for(int i=0; i)

6366

67 system("

pause");

6869

return0;

70 }

資料結構與演算法 十個排序演算法

排序演算法是 資料結構與演算法 中最基本的演算法之一,排序演算法可以分為內部和外部排序。內部排序 資料記錄在記憶體中進行排序。外部排序 因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。常見內部排序演算法 插入排序 希爾排序 選擇排序 氣泡排序 快速排序 堆排序 基數排序等。用...

資料結構與演算法 十個排序演算法之九 桶排序

桶排序是計數排序的公升級版。它利用了函式的對映關係,高效與否的關鍵就在於這個對映函式的確定。為了使桶排序更加高效,我們需要做到這兩點 在額外空間充足的情況下,盡量增大桶的數量 使用的對映函式能夠將輸入的 n 個資料均勻的分配到 k 個桶中 同時,對於桶中元素的排序,選擇何種比較排序演算法對於效能的影...

資料結構與演算法 十個排序演算法之五 歸併排序

歸併排序 merge sort 是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法 divide and conquer 的乙個非常典型的應用。作為一種典型的分而治之思想的演算法應用,歸併排序的實現由兩種方法 和選擇排序一樣,歸併排序的效能不受輸入資料的影響,但表現比選擇排序好的多,因為...