快速排序是一种典型的分治算法:选择一个数,将剩余其他数分为左右两边,左边的数均小于等于此数,右边的数均大于此数。
在这里给出两种实现思想:
1、左右指针相向而行
def partition(a):
'''
a: 输入数组
'''
m,p = 0,len(a) - 1
v = a[m]#分水岭元素,目的使得数组:小于等于v的元素在v左边,大于v的在其右边
i,j = m,p
while i < j:
#从左往右找到第一个大于v的下标i,(因为有可能所有元素都大于等于第一个元素,所以要防止i溢出,i<=p)
while i <= p and a[i] <= v:
i += 1
#从右往左找到第一个小于v的下标j
while a[j] > v:
j -= 1
#如果i在j左边,交换双方位置
if i < j:
a[i],a[j] = a[j],a[i]
#循环结束时,j所在位置为从右往左第一个小于等于v的数,将分水岭元素置于此,将a[j]放于开头,此时j左边都是小于等于v的数,右边均大于v
a[m] = a[j]
a[j] = v
return j#返回分水岭下标
def quicksort(nums):
if len(nums) <= 1:
return nums
j = partition(nums)
#分治,递归
nums[:j] = quicksort(nums[:j])
nums[j+1:] = quicksort(nums[j+1:])
return nums
#example
nums = [6,6,3,2,2,1,6,5]
print(quicksort(nums))
2、两指针同向而行
def quicksort(nums):
if len(nums) <= 1:
return nums
v = nums[0]#随机在数组中选择一个数作为分水岭,这里默认为第一个元素
left,right = 0,len(nums)-1
nums[right],nums[0] = nums[0],nums[right]
i = left - 1
for j in range(left,right):
if nums[j] <= v:
i += 1
nums[j],nums[i] = nums[i],nums[j]
i += 1
nums[i],nums[right] = nums[right],nums[i]#将分水岭元素置于从左到右第一个大于v的元素位置
#分治
nums[:i] = quicksort(nums[:i])
nums[i+1:] = quicksort(nums[i+1:])
return nums
#example
nums = [6,6,3,2,2,1,6,5]
print(quicksort(nums))
第二种思想来源于leetcode官方题解:973. 最接近原点的 K 个点