快速排序快的一点毛病没有(重新贴一下代码):
def qsort(arr,lo,hi):
if hi-lo<=1:
return
pivot=arr[lo]
i,j=lo+1,hi-1
while True:
while i<hi and arr[i]<=pivot:
i+=1
while j>lo and arr[j]>=pivot :
j-=1
if i>=j:
break
arr[i], arr[j] = arr[j], arr[i]
arr[lo], arr[j] = arr[j], arr[lo]
qsort(arr,lo,j)
qsort(arr,j+1,hi)
可是比如我是序列[1,-1,0,0,1,1,0,1,2,4,2,1,2]呢?
哦好吧,我就开始交换,交换完了是[-1, 0, 0, 0, 1, 1, 1, 1, 2, 4, 2, 1, 2]
其中枢纽元是1,最前面这个1被放到了绝对正确的位置——不用再排他了。
可是原来这个序列里好多1啊,这些我都不想排了怎么办。
那么针对这个问题,《算法》一书提到了非常好的解决办法:三相切割快速排序。
原来是二路切割,也就是分为比pivot大,或者小于等于pivot的。
这回多了个等于pivot了。
所以至少需要两个额外指针用来交换,然后递归时直接把小于,大于pivot的序列送入递归函数。
代码如下:
def qsort3(arr,lo,hi):
if hi-lo<=1:
return
pivot=arr[lo]
i,j,k=lo+1,hi-1,lo
while True:
if arr[i]<pivot:
arr[i],arr[k]=arr[k],arr[i]
i+=1
k+=1
elif arr[i]>pivot:
arr[j],arr[i]=arr[i],arr[j]
j-=1
else:
i+=1
if i>j:
break
qsort3(arr,lo,k)
qsort3(arr,j+1,hi)
我们看到了j,k分别是大于、小于pivot的边界指针,用于交换(python的交换很简洁)后,再作为新的lo,hi进入递归。
这样有效地减小了子问题大小(至少等于pivot的那一段是不用排序了)。
感谢sdgewick。