缓慢的mergesort实现,有什么不对?

时间:2010-09-20 15:26:50

标签: python sorting

我从这个mergesort实现得到意外(?)结果。与我的三向快速排序(也用python编写)相比,它非常慢。

我的quicksort在大约0.005s后完成10000个元素,而mergesort需要1.6s!包括两种实现的源代码。

归并:

#Merges two sorted lists into one sorted list. recursively
def merge(left, right):
    if len(left) == 0 and len(right) == 0:
        return []
    elif len(left) == 0:
        return right
    elif len(right) == 0:
        return left
    else:
        if left[0] <= right[0]:
            return left[:1] + merge(left[1:],right)
        else:
            return right[:1] + merge(left,right[1:])

#Splits a list in half and returns the halves
def halve(list):
    return list[:len(list)//2],list[len(list)//2:]

#Mergesort
def mergesort(list):
    if len(list) <= 1:
        return list
    left,right = halve(list)
    left,right = mergesort(left),mergesort(right)
    return merge(left,right)

快速排序:

#Three-way QuickSort in Python
def quicksort(a):
    if len(a) == 0:
        return []
    p = a[(len(a)-1)//2]
    less = quicksort([x for x in a if x < p])
    greater = quicksort([x for x in a if x > p])
    equal = [x for x in a if x == p]
    return less + equal + greater

有人可以提出解释,甚至可能解决问题吗?

4 个答案:

答案 0 :(得分:5)

关于性能的猜测通常是错误的,但是我会对此有所了解,因为我对此有一些经验。个人资料,如果你真的想要知道

您正在添加列表,即left[:1] + merge(left[1:],right),这是Python中较慢的操作之一。它会从两个列表中创建 new 列表,因此您的mergesort会创建类似N ** 2的中间列表。另一方面,快速排序使用非常快的LC而创建更少的列表(我认为像2N左右)。

尝试使用extend代替+,也许有帮助。

答案 1 :(得分:3)

递归mergesort并不是最好的做事方式。您应该通过直接迭代方法获得更好的性能。我不太熟悉Python,所以我会给你类似C的伪代码。

ileft = 0 // index into left array
iright = 0 // index into right array
iresult = 0 // index into result array
while (ileft < left.length && iright < right.length)
{
    if (left[ileft] <= right[iright])
        result[iresult++] = left[ileft++]
    else
        result[iresult++] = right[iright++]
}

// now clean up the remaining list
while (ileft < left.length)
    result[iresult++] = left[ileft++]

while (iright < right.length)
    result[iresult++] = right[iright++]

答案 2 :(得分:1)

说明:

  

通常,快速排序显着   实践中比其他Θ更快(nlogn)   算法,因为它的内循环可以   大多数人都能有效地实施   架构,在大多数现实世界中   数据,可以进行设计   最小化概率的选择   要求二次时间。

答案 3 :(得分:0)

出于好奇,我用生成器编写了一个快速实现(可能更干净)。这与原始方法相比如何?

def merge(listA,listB):
    iterA, iterB = iter(listA), iter(listB)
    valA, valB = iterA.next(), iterB.next()
    while True:
        if valA <= valB:
            yield valA
            try:
                valA = iterA.next()
            except StopIteration:
                yield valB
                try:
                    while True:
                        yield iterB.next()
                except StopIteration:
                    return
        else:
            yield valB
            try:
                valB = iterB.next()
            except StopIteration:
                yield valA
                try:
                    while True:
                        yield iterA.next()
                except StopIteration:
                    return