Python 改进合并排序
我正在练习合并排序,我很好奇我的第二个版本是否比第一个更好——这似乎是在内存需求方面,因为我是从列表中弹出的,而不是仅仅移动索引 第1版:Python 改进合并排序,python,algorithm,Python,Algorithm,我正在练习合并排序,我很好奇我的第二个版本是否比第一个更好——这似乎是在内存需求方面,因为我是从列表中弹出的,而不是仅仅移动索引 第1版: def mergesort(L): if len(L)<=1: return L pivot=len(L)/2 left=mergesort(L[:pivot]) right=mergesort(L[pivot:]) i=j=0 sortedArr=[] while i<len(left)
def mergesort(L):
if len(L)<=1: return L
pivot=len(L)/2
left=mergesort(L[:pivot])
right=mergesort(L[pivot:])
i=j=0
sortedArr=[]
while i<len(left) and j<len(right):
if left[i]<right[j]:
sortedArr.append(left[i])
i+=1
else:
sortedArr.append(right[j])
j+=1
return sortedArr + left[i:] + right[j:]
def合并排序(L):
如果len(L)为什么不使用集合中的deque?它将降低popleft()操作的成本?对于列表L
,L[:n]
操作是Python中的O(n)
时间,O(n)
空间(它创建了一个包含n
元素的新列表)
给定a
,b
,c
列表,a+b+c
是O(n)
时间和空间,其中n
是len(a)+len len(b)+len len(c)
(它还创建了一个包含n
元素的新列表)
因此,每次调用mergesort()
都需要时间和空间,即T(n)=O(n*log(n))
由于left.pop(0)
即O(len(left))
操作,您的第二个版本的时间复杂度更差。第二个版本的内存需求与第一个版本的内存需求大致相同
下面是O(n*log(n))
time,O(n)
space解决方案,具有相同的结构(使用Python 3.3+语法):
def合并排序(L):
返回列表(合并\排序\生成(L,0,len(L)))
def merge_sort_gen(L,start,n):#O(n*log(n))时间,O(n)空间
如果n==1:#始终对一个元素的列表进行排序
收益率L[起点]
elif n>1:#对半部分进行排序并合并它们
一半=n//2
合并产生的收益(合并、排序、生成(L、开始、一半),
合并\排序\生成(L,开始+一半,n-一半))
其中merge()
合并两个排序的迭代器。您可以使用或:
从functools导入部分
def merge(sorted_a,sorted_b,done=object()):#O(n)时间,O(1)空间
下一步a,下一步b=部分(下一步,已排序a,完成),部分(下一步,已排序b,完成)
a、 b=下一个a(),下一个b()
当a未完成且b未完成时:
如果b
你可以
从iterable获得的收益
产生与相同的项目(但内部细节不同):
iterable中项目的:
收益项目
请参阅。从列表前面弹出将非常低效。就内存而言,使用版本2可能会更好,但在计算方面,每个pop
都需要python将列表内存中的元素向左移动1,这将非常低效。我想您可以反转列表并弹出结尾来修复…@mgilson正在反转一个昂贵的列表?在非常优化的python代码中应该是O(N)。(您可以通过lst[::-1]
)来完成。请注意,在递归调用期间,您正在使用O(NlogN)额外内存。如果您想要一个内存高效的版本,就不应该对原始列表进行切片,而应该传递切片的开始索引和结束索引。
def mergesort(L):
if len(L)<=1: return L
pivot=len(L)/2
left=mergesort(L[:pivot])
right=mergesort(L[pivot:])
sortedArr=[]
while left!=[] and right!=[]:
if left[0]<right[0]:
sortedArr.append(left.pop(0))
else:
sortedArr.append(right.pop(0))
return sortedArr + left + right