快速排序快的一点毛病没有(重新贴一下代码):
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。