快速排序的思想就是,每一轮指定一个基准(Pivot)数,然后把小于基准数的数都放到基准数的左边,把大于基准数的数都放到基准数的右边,然后把基准数左边和右边的子数组通过递归的方式按照上述方法进行排序,最终实现整个数组有序。
输入:[49, 38, 65, 97, 76, 13, 27, 49]
首先指定一个基准数,单独拿出来,通常选择左边第一个,这里就是49。
方便描述,定义一个左指针 i i i,右指针 j j j。
然后
j
j
j从右向左扫描,找到第一个比49要小的数,找到27,放到基准数的位置:
[27, 38, 65, 97, 76, 13, -, 49]
然后
i
i
i从左向右扫描,找到第一个比49要大的数,找到65,放到上一步空出来的位置:
[27, 38, -, 97, 76, 13, 65, 49]
再次
j
j
j从右向左扫描,找到第一个比49要小的数,找到13,放到上一步空出来的位置:
[27, 38, 13, 97, 76, -, 65, 49]
再次
i
i
i从左向右扫描,找到第一个比49要大的数,找到97,放到上一步空出来的位置:
[27, 38, 13, -, 76, 97, 65, 49]
直到 i i i和 j j j碰头。
最后把基准数放到上一步空出来的位置:
[27, 38, 13, 49, 76, 97, 65, 49]
至此完成一轮。
一轮之后,在Pivot左边的数都小于或等于 49,右边的数都大于或等于49。
然后把左边的数组和右边的数组,用递归的方法,分别进行上述的排序过程。
按照这个思路,很方便写出以下代码:
def quick_sort(nums, left, right):
pivot = nums[left]
i = left
j = right
while i < j:
# 右指针j
while nums[j] >= pivot and j > i:
j -= 1
nums[i] = nums[j]
i += 1
# 左指针i
while nums[i] <= pivot and i < j:
i += 1
nums[j] = nums[i]
j -= 1
# 一轮的最后把Pivot赋值到空出来的位置
nums[i] = pivot
# Pivot左边
quick_sort(nums, left, i - 1)
# Pivot右边
quick_sort(nums, i + 1, right)
if __name__ == '__main__':
nums = [49, 38, 65, 97, 76, 13, 27, 49]
quick_sort(nums, 0, len(nums) - 1)
print(nums)
但是有些边界条件需要注意:
首先,从右向左扫描或者从左向右扫描的时候,扫完发现没有符合条件数字,那就不能进行移动操作,所以移动前需要加判断:
if j > i:
nums[i] = nums[j]
i += 1
if i < j:
nums[j] = nums[i]
j -= 1
另外,在下一轮递归前,要确保输入至少有两个数:
if left < i-1:
quick_sort(nums, left, i - 1)
if i+i < right:
quick_sort(nums, i + 1, right)
完整代码:
def quick_sort(nums, left, right):
pivot = nums[left]
i = left
j = right
while i < j:
while nums[j] >= pivot and j > i:
j -= 1
if j > i:
nums[i] = nums[j]
i += 1
while nums[i] <= pivot and i < j:
i += 1
if i < j:
nums[j] = nums[i]
j -= 1
nums[i] = pivot
if left < i-1:
quick_sort(nums, left, i - 1)
if i+i < right:
quick_sort(nums, i + 1, right)
if __name__ == '__main__':
nums = [49, 38, 65, 97, 76, 13, 27, 49]
quick_sort(nums, 0, len(nums) - 1)
print(nums)