快速排序
算法介绍
快速排序是由东尼·霍尔所发展的一种排序算法。其基本思想是,通过一趟排序将待排区间分隔成独立的两部分,然后分别对这两部分继续进行排序,以达到整个序列有序。
算法过程
-
找到标兵
-
将当前区间根据标兵分成俩部分
-
对俩个区间分别进行排序
代码实现
function quick_sort(l, r, nums) {
// 边界判断, 如果当前只剩下一个元素, 那么直接返回.
if(l >= r) return ;
// 1. 找到标兵
let x = nums[l + r >> 1], // l + r >> 1相当于Math.floor((l + r) / 2) 这样写方便一点
i = l - 1, // 让i指向左端点的前一位
j = r + 1; // 让j指向右端点的后一位
// 2. 根据标兵将数组拆分成俩部分
while(i < j) {
do i ++; while(nums[i] < x); // 从左边往右走, 找到第一个不小于x的数字
do j --; while(nums[j] > x); // 从右边往左走, 找到第一个不大于x的数字
if(i < j) [nums[i], nums[j]] = [nums[j], nums[i]]; // 若此时i < j, 交换俩数字
}
// 3. 递归处理剩余的俩个部分
quick_sort(l, j), quick_sort(j + 1, r);
}
代码讲解
- 为什么要让i指针指向左端点的前一位, j指针指向右端点的后一位
主要是为了让第二步将数组分成俩部分的代码更好实现, 使用do, while的结构会先让i++, 以及j--.
- 为什么俩个区间分别是l ~ j和j + 1 ~ r
i指针的作用是找到不小于x的数, j指针的作用是找到不大于x的数, 然后交换i和j. 最后的结果就是, j右边都是大于x的, j包括j前面的数都是小于等于x的. 所以可以根据j这个点作为分割点, 将数组分成俩部分.
复杂度分析
时间复杂度
最优时是O(NlogN)的, 最差时是O(N^2)的
-
最优: 每次都可以将数组平均分成俩半, 对于一个长度为N的数组, 需要进行logN次操作让子区间变成1, 也就是说一共会递归logN层. 在每一层我们都需要指定俩个指针扫描一遍数组的每个元素, 所以每一层需要计算N次. 层数 * 每层计算的次数 = 整个算法的时间复杂度 = O(NlogN)
-
最差: 每次选择标兵时都选到了一个最大值或最小值, 那么数组最后会被分成一个数和(N - 1)个数, 最后一共需要递归N层. 在每一层都需要遍历一遍数组, 需要N次计算. 所以整个算法的时间复杂度是O(N^2)的
空间复杂度
O(1)
只是创建了一些临时的变量, 标兵, 俩个指针. 所以是O(1)的
原题链接
AC代码
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function(nums) {
quick_sort(0, nums.length - 1);
return nums;
function quick_sort(l, r) {
if(l >= r) return ;
let x = nums[l + r >> 1],
i = l - 1,
j = r + 1;
while(i < j) {
do i ++; while(nums[i] < x);
do j --; while(nums[j] > x);
if(i < j) [nums[i], nums[j]] = [nums[j], nums[i]];
}
quick_sort(l, j), quick_sort(j + 1, r);
}
};
扩展题
有兴趣的同学可以做一下这道题目,这道题目也是基于快排的思想,用的是快速查找算法。
AC代码
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function(nums, k) {
return quick_sort(0, nums.length - 1, nums.length - k + 1);
function quick_sort(l, r, k) {
if(l >= r) return nums[l];
let i = l - 1, j = r + 1, x = nums[l + r >> 1];
while(i < j) {
do i ++; while(nums[i] < x);
do j --; while(nums[j] > x);
if(i < j) [nums[i], nums[j]] = [nums[j], nums[i]];
}
let len = j - l + 1;
if(k <= len) return quick_sort(l, j, k);
return quick_sort(j + 1, r, k - len);
}
};
本文正在参与「掘金 3 月闯关活动」,点击查看活动详情