这里介绍的快速排序与绝大部分《数据结构》教材上的并不完全一样(但是算法思想差不多,并且算法效率没有差异),笔者觉得下面这个快速排序在写法上要优雅得多,更推荐使用。
快速排序基于分治思想,
(1)选择一个轴值x;
(2)将序列划分为两部分,左半序列所有元素全 $\leqslant$ x,右半序列所有元素全 $\geqslant$ x;
(3)递归处理左半序列和右半序列。
void QuickSort(int a[], int l, int r) {
if (l >= r) return;
int i = l-1, j = r+1, x = a[(l+r)/2];
while (i < j) {
do i++; while (a[i] < x);
do j--; while (a[j] > x);
if (i < j) swap(a[i], a[j]);
}
QuickSort(a, l, j);
QuickSort(a, j+1, r);
}
注解:
(1)也可用i作划分边界:
void QuickSort(int a[], int l, int r) {
if (l >= r) return;
int i = l-1, j = r+1, x = a[(l+r+1)/2];
while (i < j) {
do i++; while (a[i] < x);
do j--; while (a[j] > x);
if (i < j) swap(a[i], a[j]);
}
QuickSort(a, l, i-1);
QuickSort(a, i, r);
}
(2)若用j作划分边界,轴值x一定不能取到a[r]
,可以写x = a[l]
、x = a[(l+r)/2]
等;若用i作划分边界,轴值x一定不能取到a[l]
,可以写x = a[r]
、x = a[(l+r+1)/2]
等。
(3)写成x = a[(l+r)/2]
与写成x = a[l]
相比,可以避免在序列原本就有序的情况下,快排复杂度退化为$O(n^2)$;随机选择轴值也能避免出现复杂度$O(n^2)$的情况,但是要排除掉轴值x为a[r]
。