
- 时间复杂度:O(N*logN)~O(N^2)
最好情况:哨兵划分 *** 作为线性时间复杂度 O(N);递归轮数共 O(logN)最坏情况:若每轮哨兵划分 *** 作都将长度为 N 的数组划分为长度为 1 和 N - 1的两个子数组,此时递归轮数达到 N轮 。 空间复杂度:O(N)非稳定: 哨兵划分 *** 作可能改变相等元素的相对顺序。
将数据组中最左/右侧的数据作为基准数,将它作为哨兵元素,值小于哨兵的放在其左侧,大于的放在其右侧。
一轮划分结束后,转换成两个较短数据组内的排序问题。
对每个短的数据组内递归进行哨兵划分,直到划分得到的子数组长度为1。
这里的swap函数我们没有使用位运算,因为这种思路的快速排序是非稳定排序,所以无法使用位运算。
static void quickSort(int[] nums, int l, int r) {
// 子数组长度为 1 时终止递归
if (l >= r) return;
// 哨兵划分 *** 作
int i = partition(nums, l, r);
// 递归左(右)子数组执行哨兵划分
quickSort(nums, l, i - 1);
quickSort(nums, i + 1, r);
}
static int partition(int[] nums, int l, int r) {
// 以 nums[l] 作为基准数
int i = l, j = r;
while (i < j) {
//从左向右找到第一个大于等于哨兵值的元素
while (i < j && nums[j] >= nums[l]) j--;
//从右向左找到第一个小于等于哨兵值的元素
while (i < j && nums[i] <= nums[l]) i++;
//分别满足两个条件的元素交换位置
swap(nums, i, j);
}
//完成一次哨兵划分后,将哨兵元素放到中间隔开两个短数组
swap(nums, i, l);
return i;
}
static void swap(int[] nums, int i, int j) {
// 交换 nums[i] 和 nums[j]
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
对于快排的空间复杂度分析,我们可以知道,最坏情况下,整个数组完全按照倒序排列,那么此时划分的递归深度为N。
如果我们首先完成一次划分后,其余每次只选择两个数组中较短的一个进行递归划分,就能保证最差的递归深度为O(logN),也就是深度最大为N/2级别
static void quickSort(int[] nums, int l, int r) {
// 子数组长度为 1 时终止递归
while (l < r) {
// 哨兵划分,得到两个数组
int mid = partition(nums, l, r);
// 比较两个数组大小,选择长度短的进行递归
if (mid - l < r - mid) {
quickSort(nums, l, mid - 1);
//每次结束后变化边界,防止溢出
l = mid + 1;
} else {
quickSort(nums, mid + 1, r);
r = mid - 1;
}
}
}
分析影响快排时间复杂度的因素可知,我们默认选择最左侧元素作为基准时,如果整个数组恰好按照倒序排序,那么每轮划分我们能完成N-1与1这种最差情况的划分。
为了大概率上避免最差情况,我们每轮划分时都可以选择随机的数据作为哨兵元素。
int partition(int[] nums, int l, int r) {
int ra = (int)(l + Math.random() * (r - l + 1));
//找到随机基准后,再将其与最左侧元素位置互换,继续按照之前的策略就可以了
swap(nums, l, ra);
int i = l, j = r;
while (i < j) {
while (i < j && nums[j] >= nums[l]) j--;
while (i < j && nums[i] <= nums[l]) i++;
swap(nums, i, j);
}
swap(nums, i, l);
return i;
}
最差情况稀疏性: 虽然快速排序的最差时间复杂度为 O(N^2),差于归并排序和堆排序,但统计意义上看,这种情况出现的机率很低。大部分情况下,快速排序以 O(NlogN) 复杂度运行。缓存使用效率高: 哨兵划分 *** 作时,将整个子数组加载入缓存中,访问元素效率很高;堆排序需要跳跃式访问元素,因此不具有此特性。常数系数低: 在提及的三种算法中,快速排序的 比较、赋值、交换 三种 *** 作的综合耗时最低(类似于插入排序快于冒泡排序的原理)。
作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/p57uhr/
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)