快排思想:
待排序数组nums[], 每一趟排序前随机选出锚点元素nums[i],该趟排序后,满足条件X:nums[i]左侧和右侧的元素分别小于和大于nums[i]。logn趟后,所有nums[i]数组元素均满足条件X,即排序完成。
算法框架:
1、sort
2、partition
1、单路快排
sort(nums, 0, n) :
start -> 0
end -> n
while (start != end) {
partitionIdx -> partition(nums, start, end);
sort(nums, start, partitionIdx);
sort(nums, partitionIdx, end);
}
每一趟排序的目的:找到满足条件X的下标index,并用nums[i] -> nums[index]。nums[i]的作用:存放比nums[i]大或者小的数组元素。
令pivot->nums[size - 1],从i=0开始往后找到第一个值大于pivot的元素时,此时下标为unmatchIdx,即nums[unmatchIdx] > pivot,此时nums[0, unmatchIdx - 1]均满足条件X,将unmatchIdx指向的空间作为存储下一个小于pivot值的空间,由于令pivot覆盖nums[size - 1],并不会丢失pivot信息,此时仅需要从pivot指向的元素的下标开始往前找到第一个值小于pivot的元素nums[k],并令nums[k] -> nums[unmatchIdx],更新unmatchIdx -> k。
重复以上步骤直到i = k,此时i为存放pivot的位置,即nums[0, i-1] <= nums[i] <= nums[i + 1, size - 1]。
选取nums[i]的门道:
1、nums[0]
2、nums[size - 1]
3、nums[random], random -> [0, size - 1]
【存在的问题】
1、数组有序时,pivot选头尾元素,会导致分隔后>pivot和
随机选择pivot可解决问题1,双路快排可解决问题2
2、双路快排
增加一个变量j,当i从左往右遍历数组时,碰到不符合小于V的数时停止,然后j从数组的右边开始遍历,碰到属于大于V的数时停止,此时我们只需要交换一下i.j指向的数据就可以了,然后重复i扫描,j扫描,交换两个数的操作,即使i和j所指向的数据相等时(都等于V)也会进行交换一次,防止了大量等于V的数据全部推到一边去了。
3、三路快排