我从这个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
有人可以提出解释,甚至可能解决问题吗?
答案 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