快速排序同归并排序一样,也采用的是分治策略。快速排序最终要的步骤是划分子数组,假设有个数组A[p..r]被划分成两个子数组(可能为空)A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A[q],且A[q]小于等于A[q+1..r]中的每个元素。划分过程伪代码如下:
PARTITION(A, p, r) x <-- A[r] i <-- p-1 for j <-- p to r-1 do if A[j] <= x then i <-- i+1 exchange A[i] <--> A[j] exchange A[i+1] <--> A[r] return i+1
此过程的c程序如下:
int partition(int A[], int p, int r) { int i, j; int x; x = A[r]; i = p-1; for (j = p; j < r; j++) { if (A[j] <= x) { swap(&A[++i], &A[j]); } } swap(&A[i+1], &A[r]); return i+1; }
快速排序伪代码如下:
QUICKSORT(A, p, r) if p < r then q <-- PARTITION(A, p, r) QUICKSORT(A, p, q-1) QUICKSORT(A, q+1, r)
c程序如下:
void quick_sort(int A[], int p, int r) { int q; if (p < r) { q = partition(A, p, r); quick_sort(A, p, q-1); quick_sort(A, q+1, r); } }
例如数组{2, 8, 7, 1, 3, 5, 6, 4},排序过程是这样的:
(1) 2 8 7 1 3 5 6 4(主元)
(2) 2 1 3 4 7 5 6 8
x为主元r,i为-1,j初值为0,因为A[0]为2小于x,所以i加1之后为0,然后交换A[0]和A[0]的值,因为相同所以原数组不变。i不变,j++到3,此时A[3]为1小于x,i加1之后为1,交换A[1]和A[3]的值,原数组变为2 1 7 8 3 5 6 4。j++到4,再交换A[2]和A[4]的值,交换后数组为2 1 3 8 7 5 6 4。j++,后面没有比x再小的数,所以for循环结束,再交换A[3]和A[7]的值,数组变为2 1 3 4 7 5 6 8,并返回3。
(3) 1 2 3 4 7 5 6 8
这样数组A被划分成了两个数组{2, 1, 3}和{7, 5, 6, 8},然后再对这两个数组进行快速排序。{2, 1, 3}数组主元为3,首先是2和2互换不变,1和1互换不变,最后3与3互换不变,这样{2, 1, 3}数组再分成两个数组{2, 1}和{3}。再对{2, 1}数组进行排序,变为{1, 2}。
{4} 1 2 3 4 5 6 7 8
再对数组{7, 5, 6, 8}进行排序,再分成两个数组{7, 5, 6}和{8},{7, 5, 6}数组排序之后变为{5, 6, 7}。
最后,完整程序如下:
#include <stdio.h> void dump(int a[], int len) { int i; for (i = 0; i < len; i++) { printf("%3d", a[i]); } printf(" "); } void swap(int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } int partition(int A[], int p, int r) { int i, j; int x; x = A[r]; i = p-1; for (j = p; j < r; j++) { if (A[j] <= x) { swap(&A[++i], &A[j]); } } swap(&A[i+1], &A[r]); return i+1; } void quick_sort(int A[], int p, int r) { int q; if (p < r) { q = partition(A, p, r); quick_sort(A, p, q-1); quick_sort(A, q+1, r); } } int main(void) { int a[] = {2, 8, 7, 1, 3, 5, 6, 4}; int len = sizeof(a) / sizeof(a[0]); dump(a, len); quick_sort(a, 0, len-1); dump(a, len); return 0; }