随机选择一个切分元素,将数组分成小于等于切分元素和大于等于切分元素的两个区间,将切分元素与小于等于切分元素的最后一个元素进行交换,即确定了切分元素排序后应在的位置,之后递归子区间,完成其他元素的排序,时间复杂度O(nlogn~n2)
具体实现,首先创建Random对象,用于确定随机切分元素,避免数组本身有序时,选择最左边元素为切分元素,需遍历剩余的所有元素才可确定切分元素排序后的位置,时间复杂度为O(n2),并且可以将等于pivot的元素平均分布在左右两个区间,避免一个区间内过多的重复元素,降低随机选择切分元素的效果。
确定切分元素排序后位置的过程定义为partition,首先确定随机切分元素,之后将其交换到数组的最前端,定义le变量,用于探索小于等于切分元素区间的右边第一个位置,定义ge变量,用于探索大于等于切分元素区间的左边第一个位置,当le<=ge,带等号可以在le=ge时继续比较,因为他俩相等时只到的元素可能从左边le++造成,但是对应的元素仍然小于pivot,le仍需++,也可能从右边ge--造成,直到的元素仍然大于pivot,ge仍需--,才可以将对应的元素包裹在正确的范围内,并且le<ge时要弹出不比较了,ge位于le左侧,说明ge对应的元素要小于等于pivot了,下面找ge对应的的位置(大于等于pivot的区间的右边的第一个元素)就不用比较了,le指向的元素严格小于切分元素时,le才右移,ge指向的元素严格大于切分元素时,ge才左移,当两个变量都停止移动时,说明对应的元素应该交换到对面的区间,进行交换,移动le,ge变量,之后循环移动,交换,直至le≥ge,结束循环,交换切分元素与ge对应的变量,返回切分元素排序后的位置,即ge变量的值。
若le=ge,并且停止移动啦,说明两个变量指向的元素为切分元素,将最左端的切分元素与他们两个指向的变量交换即可,确定切分元素排序后位置。
当le>ge时,若le先停止移动,说明le对应的元素大于切分元素,ge需要跨过它,才可以将其纳入大于等于切分元素的区间,跨过之后,ge位于le的左侧,ge对应的元素小于等于切分元素,将其与最左端的切分元素进行交换,确定切分元素排序后的位置。若ge先停止移动,说明ge对应的元素小于切分元素,le跨过它,才可以将其纳入小于等于切分元素的区间,跨过之后,le位于ge的右侧,对应的元素大于等于切分元素,ge对应的元素小于切分元素,将其与最左端的切分元素进行交换,确定切分元素排序后的位置。
LeetCode912代码,参考liweiwei大佬b站快排讲解学习。
class Solution {
Random random = new Random();
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);
}
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;
while (true) {
while (le <= ge && nums[le] < pivot) {
le++;
}
while (le <= ge && nums[ge] > pivot) {
ge--;
}
if (le >= ge) {
break;
}
swap(nums, le, ge);
le++;
ge--;
}
swap(nums, left, ge);
return ge;
}
public void swap(int[] nums, int x, int y) {
int temp = nums[x];
nums[x] = nums[y];
nums[y] = temp;
}
}