快速排序之重复元素过多的改进

快速排序快的一点毛病没有(重新贴一下代码):

def qsort(arr,lo,hi):
    if hi-lo<=1:
        return
    pivot=arr[lo]
    i,j=lo+1,hi-1
    while True:
        while ilo 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[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。

你可能感兴趣的:(算法随笔)