快速排序详解,一文搞懂切分、双路快排的做法,从0

快速排序详解,一文搞懂切分、双路快排的做法,从0

题目给你一个整数数组 nums,请你将该数组升序排列。

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

示例 1:

代码语言:javascript复制输入:nums = [5,2,3,1]

输出:[1,2,3,5]

解释:数组排序后,某些数字的位置没有改变(例如,2 和 3),而其他数字的位置发生了改变(例如,1 和 5)。示例 2:

代码语言:javascript复制输入:nums = [5,1,1,2,0,0]

输出:[0,0,1,1,2,5]

解释:请注意,nums 的值不一定唯一。快排详解快速排序的基本思想快速排序先选择一个元素作为划分的依据,一般来说是随机选择这个区间里的某一个元素

假设当前这个数组,我们选择 4 作为标准,比4小的元素有3 1 2,比4大的有6875

切分切分过程展示

最后交换 6 和 5,完成切分。

如何实现切分?

此时你可能有疑问

最后一定要记得交换left和j,才能达到partition的效果

快速排序第一版代码代码语言:javascript复制class Solution {

public int[] sortArray(int[] nums) {

// 快排是递归进行的

quickSort(nums, 0, nums.length - 1);

return nums;

}

public void quickSort(int[] nums, int left, int right) {

// ==说明只有一个元素,那就没必要再排了

if (left >= right) {

return;

}

int pivotIndex = partition(nums, left, right);

quickSort(nums, left, pivotIndex - 1);

quickSort(nums, pivotIndex + 1, right);

return;

}

public int partition(int[] nums, int left, int right) {

int pivot = nums[left];

int j = left;

// nums[left + 1..j] <= pivot

// nums(j..i) > pivot

for (int i = left + 1; i <= right; i++) {

if (nums[i] <= pivot) {

j++;

swap(nums, j, i);

}

}

swap(nums, left, j);

return j;

}

public void swap(int[] nums, int index1, int index2) {

int tmp = nums[index1];

nums[index1] = nums[index2];

nums[index2] = tmp;

}

}随机选择切分元素上面代码的问题:对于顺序数组或者逆序数组来说,递归树高度增加、递归树倾斜;

比如:

解决方案:破坏顺序性,随机选择 pivot。

代码语言:javascript复制class Solution {

// 使用当前时间的毫秒数作为随机数的种子

private static final Random random = new Random(System.currentTimeMillis());

public int[] sortArray(int[] nums) {

// 快排是递归进行的

quickSort(nums, 0, nums.length - 1);

return nums;

}

public void quickSort(int[] nums, int left, int right) {

// ==说明只有一个元素,那就没必要再排了

if (left >= right) {

return;

}

int pivotIndex = partition(nums, left, right);

quickSort(nums, left, pivotIndex - 1);

quickSort(nums, pivotIndex + 1, right);

return;

}

public int partition(int[] nums, int left, int right) {

// 随机选择基准元素

int randomIndex = left + random.nextInt(right - left + 1);

swap(nums, left, randomIndex);

int pivot = nums[left];

int j = left;

// nums[left + 1..j] <= pivot

// nums(j..i) > pivot

for (int i = left + 1; i <= right; i++) {

if (nums[i] <= pivot) {

j++;

swap(nums, j, i);

}

}

swap(nums, left, j);

return j;

}

public void swap(int[] nums, int index1, int index2) {

int tmp = nums[index1];

nums[index1] = nums[index2];

nums[index2] = tmp;

}

}双路快排上面代码的问题如下:

解决方案:

双路快排避免了递归树倾斜,递归树相对平衡;

双路快排

代码语言:javascript复制class Solution {

// 使用当前时间的毫秒数作为随机数的种子

private static final Random random = new Random(System.currentTimeMillis());

public int[] sortArray(int[] nums) {

// 快排是递归进行的

quickSort(nums, 0, nums.length - 1);

return nums;

}

public void quickSort(int[] nums, int left, int right) {

// ==说明只有一个元素,那就没必要再排了

if (left >= right) {

return;

}

int pivotIndex = partition(nums, left, right);

quickSort(nums, left, pivotIndex - 1);

quickSort(nums, pivotIndex + 1, right);

return;

}

public int partition(int[] nums, int left, int right) {

int randomIndex = left + random.nextInt(right - left + 1);

swap(nums, left, randomIndex);

int pivot = nums[left];

int le = left + 1;

int ge = right;

// nums[left + 1..le] <= pivot

// nums[ge..right] >= pivot

while (true) {

while (le <= ge && nums[le] < pivot) {

le++;

}

while (le <= ge && nums[ge] > pivot) {

ge--;

}

if (le >= ge) {

break;

}

// 我们要达到的效果就是让等于pivot的元素平均的划分到数组的两边

swap(nums, le, ge);

le++;

ge--;

}

swap(nums, left, ge);

return ge;

}

public void swap(int[] nums, int index1, int index2) {

int tmp = nums[index1];

nums[index1] = nums[index2];

nums[index2] = tmp;

}

}解释最后为什么交换 left 与 ge如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!

相关推荐

开500万豪车算什么,吴磊18岁就片酬3000万,如今身家早过亿了
收到骚扰信息怎么举报
365投注规则

收到骚扰信息怎么举报

📅 07-31 👁️ 6504
松下led吸顶灯怎么样(松下百元级LED吸顶灯对比评测)
13款gl8蓝牙功能在哪
betvip5365

13款gl8蓝牙功能在哪

📅 09-26 👁️ 6236
斑鸠吃什么(斑鸠的饮食习惯及食谱推荐)
betvip5365

斑鸠吃什么(斑鸠的饮食习惯及食谱推荐)

📅 10-23 👁️ 4376
重庆木门怎么样 (重庆木门排行榜前30名)
365dni讲解

重庆木门怎么样 (重庆木门排行榜前30名)

📅 10-22 👁️ 3183
除了巴菲特的价值投资,还有哪些投资方法?
芎藭的药方
365dni讲解

芎藭的药方

📅 09-06 👁️ 7332
详细解析快手视频剪辑技巧与教程,轻松掌握视频编辑方法