数据结构与算法——十个排序算法之六 · 快速排序
1. 快速排序介绍
快速排序是由 东尼·霍尔 所发展的一种排序算法。在平均状况下,排序 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) 的归并排序要小很多。所以对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
2. 步骤说明
对于下面待排序的数组:
| 163 | 161 | 158 | 165 | 171 | 170 | 163 | 159 | 162 |
第一步:先选择第一个数 163 为基准数,以 163 为基准将小于它的数排在它前面,大于等于它 的数排在其后,结果如下:
| 162 | 161 | 158 | 159 | 163 | 170 | 163 | 171 | 165 |
具体排列数据的步骤:
1. 确定 163 为基准数后,先把 163 从数组中取出来
| 161 | 158 | 165 | 171 | 170 | 163 | 159 | 162 |
2. 然后从最右端开始,查找小于基准数 163 的数,找到 162,将其移至空出来的元素中,
| 162 | 161 | 158 | 165 | 171 | 170 | 163 | 159 |
3. 接下来,从最左边未处理的元素中从左至右扫描比基数 163 大的数,将其移动至右侧空出 来的元素中
| 162 | 161 | 158 | 171 | 170 | 163 | 159 | 165 |
4. 接下来,继续从最右边未处理的元素中从右至左扫描比基数 163 小的数,将其移动至左侧 空出来的元素中
| 162 | 161 | 158 | 159 | 171 | 170 | 163 | 165 |
接下来再重复执行步骤 3,171 执行右移
| 162 | 161 | 158 | 159 | 170 | 163 | 171 | 165 |
重复执行步骤 4,此时右边的值已经均大于基数,左边的值均已小于基数
| 162 | 161 | 158 | 159 | 170 | 163 | 171 | 165 |
接下来我们将基数保存回黄色空格中
| 162 | 161 | 158 | 159 | 163 | 170 | 163 | 171 | 165 |
第二步:采用分治法分别对基数左边和右边的部分运用第一步中的方法进行递归操作,直到整个 数组变得有序,以左边的数组为例:
| 162 | 161 | 158 | 159 |
选择 162 为基数,挪移得到结果如下:
| 159 | 161 | 158 | 162 |
以 162 为界,把数组分成两个部分,此时,基数右侧已经没有数据,所以,接下来只要继续 对左侧的数组分治处理即可,选择 159 为基数,再次挪移得到结果如下:
| 158 | 159 | 161 |
总结:
-
从数列中挑出一个元素,称为 "基准"(pivot);
-
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
-
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
动图演示(来源 runoob.com):

代码实现:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int partition(int arr[], int low, int high) 5 { 6 int i = low; 7 int j = high; 8 int base = arr[low]; 9 10 if(low < high) 11 { 12 while(i < j) 13 { 14 while(i < j && arr[j] >= base) 15 { 16 j--; 17 } 18 19 if(i < j) //右边已经找到小于基数的数 20 { 21 arr[i++] = arr[j]; 22 } 23 24 while(i < j && arr[i] < base) 25 { 26 i++; 27 } 28 29 if( i < j) //左边已经找到大于基数的数 30 { 31 arr[j--] = arr[i]; 32 } 33 } 34 arr[i] = base; 35 } 36 return i; 37 } 38 39 void QuickSort(int *arr, int low, int high) //实现快速排序 40 { 41 if(low < high) 42 { 43 int index = partition(arr, low, high); 44 QuickSort(arr, low, index-1); 45 QuickSort(arr, index+1, high); 46 } 47 } 48 49 int main(void) 50 { 51 int arr[] = {163, 161, 158, 165, 171, 170, 163, 159, 162}; 52 int len = sizeof(arr)/sizeof(arr[0]); 53 54 /*int index = partition(arr, 0, len-1); 55 printf("分区完毕, 基数下标: %d\n", index); 56 */ 57 58 QuickSort(arr, 0, len-1); 59 60 printf("执行快速排序后的结果:\n"); 61 62 for(int i=0; i<len; i++) 63 { 64 printf(" %d", arr[i]); 65 } 66 67 system("pause"); 68 69 return 0; 70 }
====================================================================================================================================


浙公网安备 33010602011771号