之前的几次面试都有问到快速排序,我的写法都是按照算法导论上随便写写的:
一:基本快速排序:(参照算法导论)
#快速排序
def quicksort(nums,p,r):
if p<r:
q=partition(nums,p,r)
quicksort(nums,p,q-1)
quicksort(nums,q+1,r)
return
def partition(nums,p,r):
x=nums[r]
i=p-1 #记录位置
for j in range(p,r):
if nums[j]<=x:
i+=1
nums[i],nums[j]=nums[j],nums[i]
nums[i+1], nums[r] = nums[r], nums[i+1]
return i+1
二:偶尔会问怎么改成非递归的
def quicksort2(nums,p,r):
#非递归实现,只需要申请一个 栈来记录 需要排序的起始位置与终点位置
stack=[p,r]
while stack:
new_r=stack.pop()
new_p=stack.pop()
q=partition(nums,new_p,new_r)
if new_p<q-1:
stack.extend([new_p,q-1])
if new_r>q+1:
stack.extend([q+1,new_r])
return nums
三:写成一个函数
def quicksort(nums,p,r):
if p>=r:return
x=nums[r]
i=p-1 #记录位置
for j in range(p,r):
if nums[j]<=x:
i+=1
nums[i],nums[j]=nums[j],nums[i]
nums[i+1], nums[r] = nums[r], nums[i+1]
q=i+1
quicksort(nums,p,q-1)
quicksort(nums,q+1,r)
return
四:如果从前端取值:
def quicksort(nums,p,r):
if p>=r:return
x=nums[p]
i=p #记录位置
for j in range(p+1,r+1):
if nums[j]<x:
i+=1
nums[i],nums[j]=nums[j],nums[i]
#最后的结果:nums[p+1,,,,i-1]都小于x;nums[i,...,r]>=x
nums[i], nums[p] = nums[p], nums[i]
quicksort(nums,p,i-1)
quicksort(nums,i+1,r)
return
五:改进一:
考虑极端的情况:如果n个数都相同,插入排序是O(n),而快排则变成了平方级别的。
考虑从两端划分:
i从左往右扫,j从右往左扫;
如果i>=j循环终止
否则交换i,j对应的值(这里相当于又找到了一个大于等于key和一个小于等于key的数,i++,j–)
(python没有do while 写成这个会比较简单)
def quicksort(nums,p,r):
if p>=r:
return
key=nums[p]
i=p+1 #从左往右
j=r #从右往左
while True:
while i<=r and nums[i]<key:
i+=1
while nums[j]>key:
j-=1
if i>=j:
break
#此时nums[p+1,,,i-1]都小,注意i可能为r+1
#nums[j+1,r]都大
nums[i],nums[j]=nums[j],nums[i]
i+=1
j-=1
nums[p],nums[j]=nums[j],nums[p]
quicksort(nums,p,i-1)
quicksort(nums,j+1,r)
return
六:改进二:
如果对于排序好的数,选取第一个元素做划分会导致效率的降低(平方级别)。
所以应该选择随机选择划分元素.
在 if的后面加上:
x=random.randint(p,r)
nums[x],nums[p]=nums[p],nums[x]
七:改进三:
修改 if
快速排序花费了大量的时间来排序很小的子数组,如果采用插入排序会更快
可以修改为:
if p-r<cutoff:
return
其中,cutoff是一个小整数,然后选择其他排序算法进行排序。