1. 程式人生 > 實用技巧 >資料結構與演算法複習(一)快速排序

資料結構與演算法複習(一)快速排序

快速排序的步驟是:
1、在陣列中任意選擇一個元素,稱為軸值
2、掃描陣列,將大於等於軸值的元素放到軸的右邊,將小於軸值的元素放到軸的左邊;固定軸的位置不動,
於是,陣列被分為大於軸值和小於軸值的兩個部分
4、對軸兩邊的陣列遞迴執行1和2兩個步驟

before sort :
開始時選擇最後一個元素40為軸
27 28 1 59 48 63 40
掃描陣列,將大於等於40的元素放到40的右邊,將小於40的元素放到40的左邊
同樣的,固定40的位置不動,對40兩邊的陣列遞迴進行上述過程
27 28 1 40 48 63 59
1 28 27 40 48 63 59
1 27 28 40 48 63 59
1 27 28 40 48 59 63

after sort :
1 27 28 40 48 59 63

快速排序是一種非穩定演算法(比如陣列84 84,排序時兩者會交換)。
每一趟劃分都需要對劃分陣列的所有元素掃描一遍,那麼每一趟劃分需要的時間為O(n);
因此快速排序的時間複雜度取決於劃分的次數,
理想的情況下,每次劃分都能將陣列對半分,那麼只需要劃分log2n次,則時間複雜度為O(nlog2n);
最壞情況下,每次劃分都選擇到最大或最小元素作為軸,那麼需要劃分n次,則時間複雜度為O(n*n);
被證明是:快速排序的平均時間複雜度為O(nlog2n)。

快速排序的空間複雜度:只需要一個數據快取作為交換空間;每劃分一次需要入棧一次,因此需要的棧空間為劃分次數。因此快速排序的空間複雜度為劃分次數。

綜上所述:快速排序的效能取決於軸值的合理性,因此在排序時要採用一些辦法選擇合適的軸值,比如隨機法。

演算法實現程式碼如下。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 /* 用時間做種子產生隨機數 */
 5 #include <time.h>
 6 
 7 void quicksort(int A[], int left, int right)
 8 {
 9     /*
10      * left:陣列左下標
11      * right:陣列右下標
12 */ 13 int l, r; 14 15 if (A == NULL || left >= right) { 16 return; 17 } 18 19 l = left; 20 r = right - 1; 21 while (l <= r) { 22 while (A[l] < A[right]) {++l;} 23 while (r >= left && A[r] >= A[right]) {--r;} 24 25 if (r >= left) { 26 exchange(A, l, r); 27 } 28 } 29 30 if (r >= left) { 31 exchange(A, l, r); 32 } 33 /* 將軸換到l的位置,並將l作為陣列分割點 */ 34 exchange(A, l, right); 35 quicksort(A, left, l - 1); 36 quicksort(A, l + 1, right); 37 } 38 39 static void printA(int A[], int len) 40 { 41 int i; 42 43 for (i = 0; i < len; i++) { 44 printf("%d ", A[i]); 45 } 46 printf("\n"); 47 } 48 49 int main(int argc, char **argv){ 50 int i, res, len; 51 int A[50]; // = {-1,6,2,3,9,19}; 52 53 srand((int)time(NULL)); 54 len = rand() % 51; //51; 55 printf("len is %d.\n", len); 56 57 srand((int)(time(NULL) + len)); 58 for (i = 0; i < len; i++) { 59 A[i] = rand() % 100; 60 } 61 62 printf("before sort :\n"); 63 printA(A, len); 64 65 quicksort(A, 0, len - 1); 66 67 printf("after sort :\n"); 68 printA(A, len); 69 70 return 0; 71 }