前两天遇到了一道用快速排序来做的题,脑子里有思路但就是做不出来,总是因为一些边界条件排不对,其实快排我之前看过,但是,,,很久没接触就又忘记了,这次就来记录一下。
首先,“分而治之”就是把一个大问题分解成很多个小问题,逐个把小问题解决掉。而具体的“小问题”有多小呢?举个例子,如果一个列表里只有一个元素,那么对这个列表做任何操作(排序?根本不用排,只有一个元素跟谁排,直接返回就行啦 >_<)都会非常轻松。
我们要做的就是将一个长列表分到很多个只有一个元素的短列表,同时在“分”的过程中做出合适的操作(这里是重点),最后将所有的短列表结果合在一起就是最终的答案。
以列表nums1 = [1, 3, 2, 0, 4, 5, 6, 7, 9, 10, 8]为例:
设置第一个元素为pivot,进行第一轮查找:
第二轮查找:
第三轮,发现l>r,已经不符合循环条件了,交换r和pivot,可以发现此时的pivot左边都是不大于它的数,右边都是不小于它的数:
1) 将一个列表整体排好序,说明列表中每一个元素都在自己正确的位置上(比如有列表 [2,3,1] 需要按升序排列,那么排好序后,元素3就一定要在第三个位置上)。
2) 反过来想,也就意味着,将列表中每一个元素都放到它该在的位置上,整个列表就排好序了。
3) 如何找到一个元素的正确位置?
4) 若为升序排序,则该元素的左边都是<=自己的元素,右边都是>=自己的元素;降序排序同理,左>=自己,右<=自己。
5)如果该元素满足上面的条件,那么不管其他元素是不是有序的,反正自己是排好了,自己就在这个位置不动了,其他元素就让他们自己排去吧。
6)最后,是快速排序需要传入的参数(列表,起始下标,终止下标):
def quick_sort(nums, start, end):
就是上面说到的,如果列表中只有一个元素,不用排序,直接返回即可。也就是列表的起始 start = end 的情况;如果 start > end 是显然不符合的,至于为什么会出现这种情况,有两种,下面解释“分治模块”的第三条会提到。
if start >= end:
return
选择一个要排的元素记为 pivot(看了好多大佬快排都用这个单词,我也用,这样就会显得我很专业吼吼吼,单词英文解释:支点; 枢轴; 核心),可以选择列表起始的元素 nums[start];设置左右双指针 l 和 r,并初始化为 start 和 end。
pivot, l, r = nums[start], start, end
在左指针小于右指针的前提下:
首先从右往左找到第一个比 pivot 小的元素:
while l < r:
while nums[r] >= pivot and l < r:
r -= 1
再从左到右找到第一个比 pivot 大的元素:
while nums[l] <= pivot and l < r:
l += 1
当 l 和 r 都找到后,交换两个值:
nums[l], nums[r] = nums[r], nums[l]
判断此时 l 和 r 的关系,如果仍然 l < r ,继续上述操作;否则跳出循环,交换之前选做 pivot 的 nums[start] 元素,将其与 下表为 r 的值进行交换:
(由于有 l < r 的约束,这一步最多有 i = j)
nums[start], nums[r] = nums[r], nums[start]
1)此时,下标为 r 的元素(就是之前选的 pivot)已经排在了正确的位置,左边都 <= pivot,右边都 >= pivot,那么我们再对左半部分 nums 和右半部分 nums 分别进行排序即可。
2)左边的起始下标仍为 start,终止下标变成了 r-1,因为 nums[r] 已经排好序不用再加上了;右边同理,起始为 r+1,终止为 end。
3)如果最后一轮排序找到的 r 就等于列表起始下标start,或者 r 就等于列表终止下标end,那么显然start > r-1 或者 r+1>end,则下一次的quick_sort 中有 start>end,所以终止条件中会有出现 start>end 时直接返回的这种情况。
quick_sort(nums, start, r - 1)
quick_sort(nums, r + 1, end)
def quick_sort(nums, start, end):
if start >= end:
return
pivot, l, r = nums[start], start, end
while l < r:
while nums[r] >= pivot and l < r:
r -= 1
while nums[l] <= pivot and l < r:
l += 1
nums[l], nums[r] = nums[r], nums[l]
nums[start], nums[r] = nums[r], nums[start]
# print(start, end, l, r, nums)
quick_sort(nums, start, r - 1)
quick_sort(nums, r + 1, end)
def f(nums):
quick_sort(nums, 0, len(nums) - 1)
return nums
nums1 = [3, 2, 3, 1, 2, 4, 5, 5, 6]
print(f(nums1))
最后,quick_sort 代码中的 return 没有返回任何值,因为操作都是在列表 nums 上直接完成的。如果大家有什么看法和疑问,欢迎留言哦。