快速排序:
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
步骤为:
- 从数列中挑出一个元素,称为 "基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
这种分治的方法不同于希尔排序和归并排序,希尔排序是取增量,归并排序是2n阶分治,而快速排序的分治是折中。
1 #include <stdio.h> 2 int a[100] = { 1, 2, 8, 7, 9, 5, 6, 4, 3, 66, 77, 33, 22, 11 }; 3 4 /* 输出数组前n各元素 */ 5 void prt(int n) { 6 int i; 7 for (i = 0; i < n; i++) { 8 printf("%d ", a[i]); 9 } 10 printf(" "); 11 } 12 13 /* 数据交换 */ 14 void swap(int *a, int *b) 15 { 16 int tmp; 17 tmp = *a; *a = *b; *b = tmp; 18 } 19 20 void quick_sort(int a[], int left, int right) 21 { 22 int i = left + 1, j = right; 23 int key = a[left]; 24 25 if (left >= right) return; 26 27 /* 从i++和j--两个方向搜索不满足条件的值并交换 * 28 * 条件为:i++方向小于key,j--方向大于key */ 29 while (1) { 30 while (a[j] > key) j--; 31 while (a[i] < key&&i<j) i++; 32 if(i >= j) break; 33 swap(&a[i],&a[j]); 34 if(a[i]==key)j--; 35 else i++; 36 } 37 38 /* 关键数据放到‘中间’ */ 39 swap(&a[left],&a[j]); 40 41 if(left < i - 1) quick_sort(a, left, i - 1); 42 if(j + 1 < right) quick_sort(a, j + 1 , right); 43 44 } 45 46 int main(void) { 47 48 /* 排序与输出 */ 49 quick_sort(a, 0, 13); 50 prt(14); 51 52 return 0; 53 }
快速排序也可以看做是冒泡排序的一种递归优化版本。