快速排序 quick sort


https://github.com/hotwater99/practice_datastructure_and_algorithm.git

《数据结构与算法分析——C语言描述》机械工业出版社,原书第2版,7.7


快速排序的思路是在数组中设定一个数为“枢纽元”,比“枢纽元”小的数全部放到“枢纽元”的左边;比“枢纽元”大的数全部放到“枢纽元”的右边。然后采用分治的方法分别处理左边右边的数组,这样就可以完成排序了。

GIF 2020-4-29 15-19-25
在实际操作时,主要有两个问题对效率影响较大:

1、如何找到合适的枢纽元pivot;

2、如何对数组进行分割(分割成比枢纽元大的、小的两个子数组)。


用Median函数确定枢纽元。首先在数组中把Left,Right,Center这3个位置上的数拿出来,把其中最小的放到Left,最大的放到Right,剩下的那个就作为枢纽元,为了提高效率,把Center与Right-1的位置数交换一下,把枢纽元保存在Array[Right-1],这样后续只要处理Array[Left+1]到Array[Right-2]就好了。


数组分割。用i, j两个光标,i从Array[Left+1]开始,从左往右扫描,遇到≥pivot的就停止;j从Array[Right-2]开始,从右往左扫描,遇到≤pivot的就停止。i和j扫描都停止后,就交换Array[i]和Array[j],最后直到i和j两个交叉了为止。最后将枢纽元所在的Array[Right-1]与Array[i](i停止时Array[i]≥pivot)交换一下,这样就完成了数组分割。


快速排序:

  1 // 返回“左端、中心、右端”中数值处于中间的那个,即枢纽元pivot
  2 // 处理“左端、中心、右端”,并隐藏枢纽元pivot
  3 int Median(int array[], int left, int right)
  4 {
  5   int center = (left + right) / 2;
  6 
  7   if (array[left] > array[center])
  8     Swap(&array[left], &array[center]);
  9   if (array[left] > array[right])
 10     Swap(&array[left], &array[right]);
 11   if (array[center] > array[right])
 12     Swap(&array[center], &array[right]);
 13 
 14   Swap(&array[center], &array[right - 1]); // hide pivot
 15   return array[right - 1];
 16 }
 17 
 18 void QSort(int array[], int left, int right)
 19 {
 20   int i, j;
 21   int pivot;
 22 
 23   if (left + CUT_OFF <= right) {
 24     pivot = Median(array, left, right);
 25     i = left;
 26     j = right - 1;
 27     for (;;) {
 28       while (array[++i] < pivot) {}
 29       while (array[--j] > pivot) {}
 30       if (i < j)
 31         Swap(&array[i], &array[j]);
 32       else
 33         break;
 34     }
 35     Swap(&array[i], &array[right - 1]);
 36     QSort(array, left, i - 1);
 37     QSort(array, i + 1, right);
 38   }
 39   else {
 40     // 数组长度太短时,用插入排序效率更高
 41     InsertSort(array + left, right - left + 1);
 42   }
 43 }
 44 
 45 void QuickSort(int array[], int N)
 46 {
 47   QSort(array, 0, N - 1);
 48 }


完整代码:

  1 #include <iostream>
  2 #include <ctime>
  3 
  4 using namespace std;
  5 
  6 #define random(x)       (rand()%x)
  7 #define ARRAY_LENTH     10
  8 
  9 #define CUT_OFF         3 // 数组长度太短时,用插入排序效率更高
 10 
 11 void InsertSort(int array[], int n)
 12 {
 13   int i, j;
 14   int tmp;
 15 
 16   for (i = 1; i < n; i++)
 17   {
 18     tmp = array[i];
 19 
 20     for (j = i; j > 0 && array[j - 1] > tmp; j--) {
 21       array[j] = array[j - 1];
 22     }
 23     array[j] = tmp;
 24   }
 25 }
 26 
 27 void Swap(int *a, int *b)
 28 {
 29   int tmp = *a;
 30   *a = *b;
 31   *b = tmp;
 32 }
 33 
 34 // 返回“左端、中心、右端”中数值处于中间的那个,即枢纽元pivot
 35 // 处理“左端、中心、右端”,并隐藏枢纽元pivot
 36 int Median(int array[], int left, int right)
 37 {
 38   int center = (left + right) / 2;
 39 
 40   if (array[left] > array[center])
 41     Swap(&array[left], &array[center]);
 42   if (array[left] > array[right])
 43     Swap(&array[left], &array[right]);
 44   if (array[center] > array[right])
 45     Swap(&array[center], &array[right]);
 46 
 47   Swap(&array[center], &array[right - 1]); // hide pivot
 48   return array[right - 1];
 49 }
 50 
 51 void QSort(int array[], int left, int right)
 52 {
 53   int i, j;
 54   int pivot;
 55 
 56   if (left + CUT_OFF <= right) {
 57     pivot = Median(array, left, right);
 58     i = left;
 59     j = right - 1;
 60     for (;;) {
 61       while (array[++i] < pivot) {}
 62       while (array[--j] > pivot) {}
 63       if (i < j)
 64         Swap(&array[i], &array[j]);
 65       else
 66         break;
 67     }
 68     Swap(&array[i], &array[right - 1]);
 69     QSort(array, left, i - 1);
 70     QSort(array, i + 1, right);
 71   }
 72   else {
 73     // 数组长度太短时,用插入排序效率更高
 74     InsertSort(array + left, right - left + 1);
 75   }
 76 }
 77 
 78 void QuickSort(int array[], int N)
 79 {
 80   QSort(array, 0, N - 1);
 81 }
 82 
 83 int main() {
 84   int test_array[ARRAY_LENTH];
 85   int i, N = ARRAY_LENTH;
 86   clock_t start_time, stop_time;
 87 
 88   for (i = 0; i < N; i++) {
 89     test_array[i] = random(N);
 90   }
 91 
 92   if (N <= 100) {
 93     cout << "raw : ";
 94     for (i = 0; i < N; i++) {
 95       cout << test_array[i] << " ";
 96     }
 97     cout << endl;
 98   }
 99 
100   start_time = clock();
101 
102   QuickSort(test_array, N);
103 
104   stop_time = clock();
105 
106   if (N <= 100) {
107     cout << "sort: ";
108     for (i = 0; i < N; i++) {
109       cout << test_array[i] << " ";
110     }
111     cout << endl;
112   }
113 
114   cout << "QuickSort(" << N << ")..." << endl;
115   cout << "total time used: ";
116   cout << (double)(stop_time - start_time) / CLOCKS_PER_SEC << "s" << endl;
117 
118   system("pause");
119 
120   return 0;
121 }


测试结果


N=10

raw : 1 7 4 0 9 4 8 8 2 4
sort: 0 1 2 4 4 4 7 8 8 9
QuickSort(10)...
total time used: 0s

N=100

raw : 41 67 34 0 69 24 78 58 62 64 5 45 81 27 61 91 95 42 27 36 91 4 2 53 92 82 21 16 18 95 47 26 71 38 69 12 67 99 35 94 3 11 22 33 73 64 41 11 53 68 47 44 62 57 37 59 23 41 29 78 16 35 90 42 88 6 40 42 64 48 46 5 90 29 70 50 6 1 93 48 29 23 84 54 56 40 66 76 31 8 44 39 26 23 37 38 18 82 29 41
sort: 0 1 2 3 4 5 5 6 6 8 11 11 12 16 16 18 18 21 22 23 23 23 24 26 26 27 27 29 29 29 29 31 33 34 35 35 36 37 37 38 38 39 40 40 41 41 41 41 42 42 42 44 44 45 46 47 47 48 48 50 53 53 54 56 57 58 59 61 62 62 64 64 64 66 67 67 68 69 69 70 71 73 76 78 78 81 82 82 84 88 90 90 91 91 92 93 94 95 95 99
QuickSort(100)...
total time used: 0s

N=1000

QuickSort(1000)...
total time used: 0s
N=10000
QuickSort(10000)...
total time used: 0.001s

N=100000

QuickSort(100000)...
total time used: 0.011s



posted @ 2020-04-29 16:47  hotwater99  阅读(325)  评论(0编辑  收藏  举报