快速排序
排序就是将一组对象按照某种逻辑顺序重新排列的过程。
在本文中我们使用的操作:
- 遍历数组
- 比较两个对象(本文中所有代码示例中的less方法)
- 交换两个对象 (本文中所有代码示例中的exch方法)
less 、 exch方法的源码:
private static boolean less(Comparable v, Comparable w) {
return (v.compareTo(w) < 0);
}
private static void exch(Comparable[] a, int i, int j) {
Comparable swap = a[i];
a[i] = a[j];
a[j] = swap;
}
快速排序的基本思路是通过以下手段将每一个对象移动到对的位置:
1. 选取第一个对象a;
2. 从左往右搜索到比a大的对象c,从右往左搜索到比a小的对象d;
3. 交换c和d;
4. 继续2直到左右两个方向的搜索在e对象的位置相遇,交换a和e,这样a的位置就确定下来了;
5. 分别对a左边和右边的数组应用1、2、3、4、5;
快速排序过程示例:
基本快速排序
- 首先是第1步到第4步的算法:
private static int partition(Comparable[] a, int lo, int hi) {
int i = lo;
int j = hi + 1;
Comparable v = a[lo];
while (true) {
// find item on lo to swap
while (less(a[++i], v)) { //从左往右搜索比v大的对象
if (i == hi) break;
}
// find item on hi to swap
while (less(v, a[--j])) { //从右往左搜索比v大的对象
if (j == lo) break; // redundant since a[lo] acts as sentinel
}
// check if pointers cross
if (i >= j) break; //两边搜索交叉说明没有需要交换的对象
exch(a, i, j); //交换找到的对象
}
// put partitioning item v at a[j]
exch(a, lo, j); //将当前被排序的对象交换到对的位置
// now, a[lo .. j-1] <= a[j] <= a[j+1 .. hi]
return j;
}
- 递归执行的过程:
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int j = partition(a, lo, hi); //先为第一个对象找到位置
sort(a, lo, j-1); //递归排序左边子数组
sort(a, j+1, hi); //递归排序右边子数组
}
算法改进
- 切分元素的选取会影响开始排序的效率,所以一般在排序之前会随机打乱原数组的位置;以及采用所谓三取样切分的方法选取切分元素即在被排序数组中随机选取三个对象,并选择三个中位于中间的元素来作为切分元素;
- 在小数组时使用插入排序来代替递归调用;
- 当数组中重复元素较多时使用三向切分的快速排序算法,除了大于和小于还考虑等于的部分,代码如下:
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int lt = lo, gt = hi;
Comparable v = a[lo];
int i = lo + 1;
while (i <= gt) {
int cmp = a[i].compareTo(v);
if (cmp < 0) exch(a, lt++, i++);
else if (cmp > 0) exch(a, i, gt--);
else i++; //当与被排序元素相等时直接跳过
}
// a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi].
sort(a, lo, lt-1);
sort(a, gt+1, hi);
}
性能与特性
- 稳定性:不稳定。
- 空间:由于是递归执行,所以需要消耗栈空间,其空间复杂度为O($ lgN$) 。
- 时间:对于基本的快速排序算法,其平均时间复杂度为O( N l o g N NlogN NlogN),对于三向快速排序算法,其时间复杂度介于 O(N) 到 O( N l o g N NlogN NlogN)之间。
参考资料
- 算法(第四版)Robert Sedgewick 和 Kevin Wayne 著
- https://algs4.cs.princeton.edu/21elementary/ (文中所有代码来源)