特性:
| 排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 |
|---|---|---|---|
| 快速排序 | O(nlogn) |
O(logn) |
不稳定 |
和归并排序的对比
| 快速排序 | 归并排序 | |
|---|---|---|
| 特点 | 两个子数组都有序时,则整个数组也就自然有序了 | 将数组分成两个子数组分别排序,并将有序的子数组归并 |
| 切分 | 取决于数组的内容 | 等分两半 |
思路:
选取一个“切分“点,确保:
- 切分点的左侧都小于它。
- 切分点的右侧都大于它。
- 分别对切分点进行排序
过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。
伪代码:
function quickSort(a, lo, hi) {if (hi <= lo) return;const j = partition(a, lo, hi); // 切分,快速排序的关键quickSort(a, lo, j - 1);quickSort(a, j + 1, hi);}
切分
const { less, exch } = require('./util');function partition(a, lo, hi) {let i = lo;let j = hi + 1;// 随意选取a[lo]做为切分元素const v = a[lo];while(1) {// 从数组的左端开始向右扫描,直到寻找到一个大于等于v的元素while(less(a[++i], v])) if(i === hi) break;// 从数组的右端开始向左扫描,直到寻找到一个小于等于v的元素while(less(v, a[--j])) if (j === lo) break;// 边界条件:如果指针相遇,则退出循环if(i >= j) break;// 调换他们的位置,一定可以找到,如果找不到则在上一步终止了exch(a, i, j);}// 交换v和指针相遇位置的值exch(a, lo, j);return j;}
实现
const { less, exch, getArr } = require('../utils');function partition(arr, lo, hi) {let i = lo;let j = hi + 1;// 随意选取一个作为“切分”点const v = arr[lo];while (1) {// 从左到右寻找到大于 v 的值(下标)while (less(arr[++i], v)) {if (i === hi) break;}// 从右到左寻找到小于 v 的值(下标)while (less(v, arr[--j])) {if (j === lo) break;}// 如果指针(下标)对撞则终止循环if (i >= j) break;// 交换小的值exch(arr, i, j);}exch(arr, lo, j);return j;}function quickSort(arr, lo, hi) {if (lo === undefined) {lo = 0;hi = arr.length - 1;}if (lo >= hi) return;const j = partition(arr, lo, hi); // 获取切分点quickSort(arr, lo, j - 1);quickSort(arr, j + 1, hi);return arr;}
算法改进
切换到插入排序
小数组使用使用插入排序吧,长度在5-15内用这个,很快;
三取样切分
使用子数组的一小部分元素的中位数来切分数组,代价是需要计算中位数。
三向切分的快速排序
针对重复数据比较多的数组。
function quick3way(a, lo, hi) {if (hi <= lo) return;let lt = lo; // a[lo, ...lt - 1]中的所有元素都小于vlet gt = hi; // a[gt + 1, ...hi]中的所有元素都大于vlet i = lo + 1; // a[lt, ...i]中的所有元素都等于v// a[i, ...gt] 中的元素还未确定let v = a[lo];while(i <= gt) {let cmp = a[i] - v;// a[i] < v,交换 a[lt] 和 a[i],lt指针、i指针右移,将小于v的都放到v的右边if (cmp < 0) exch(a, lt++, i++);// a[i] > v,交换 a[i] 和 a[gt],gt左移,将大于v的都迁移到v的右边else if (cmp > 0) exch(a, i, gt--);// 相等情况移动i指针else i++}sort(a, lo, lt - 1);sort(a, gt + 1, hi);}
