2013-12-09 21 views
1
def mergesort(a): 
    if len(a)<=1: 
     return a 

    else: 
     mid=len(a)/2 
     mergesort(a[:mid]) 
     mergesort(a[mid:]) 
     auxa=[] 
     j=0 
     k=mid 
     while j<mid and k<len(a): 
      if a[j]<a[k]: 
       auxa.append(a[j]) 
       j+=1 
      else: 
       auxa.append(a[k]) 
       k+=1 

     if j==mid: 
      auxa.extend(a[k:]) 

     if k==len(a): 
      auxa.extend(a[j:mid]) 

     a=auxa 


     return a 

testlist=[3,2,1] 
print mergesort(testlist) 

结果我得到的是2 1 3Mergesort in Python,我的第一个排序算法,出了什么问题?

任何帮助非常感谢,谢谢!

+0

不要忽略内部'归并返回值()'调用 – jfs

回答

4

您的函数mergesort返回一个新列表,并且不会修改您提供的列表,因为您似乎期望它正在执行。因此,例如,当您拨打mergesort(a[:mid])时,返回的是这些元素的新排序版本,而原始a[:mid]保持完全相同。

编辑:这里的问题是python列表切片工作的方式。当你说a[:mid]时,python会创建一个'copy'(我们不用担心原始文件的确切类型)。现在,当您在函数中修改此副本时,您所做的只是将其中的引用更改为指向新整数,而不是以任何方式修改原始副本。下面是一些代码以充实了这一点:

def change(a): 
    a[1] = 0 

a = [1, 2, 3] 
change(a) 
a 
>> [1, 0, 3] 

a = [1, 2, 3] 
change(a[:2]) 
a 
>> [1, 2, 3] 

编辑2:复制回(中发表的意见(abamert的建议))做正确的价值观:

def mergesort(a): 
    if len(a)<=1: 
    return a 

    else: 
    mid=len(a)/2 
    a = mergesort(a[:mid]) + mergesort(a[mid:]) 
    auxa=[] 
    j=0 
    k=mid 
    while j<mid and k<len(a): 
     if a[j]<a[k]: 
      auxa.append(a[j]) 
      j+=1 
     else: 
      auxa.append(a[k]) 
      k+=1 

    if j==mid: 
     auxa.extend(a[k:]) 

    if k==len(a): 
     auxa.extend(a[j:mid]) 


    return auxa 

这显然是更好的方式做这涉及到较少的复制,但我认为这个解决方案与原始代码的问题稍有关系。

+0

很好的解释,但我想你也想提供_solution_。如果你想改变前半部分,只要执行'a [:mid] = mergesort(a [:mid])''。或者,更好的办法是使用'a = mergesort(a [:mid])+ mergesort(a [mid:])'在两个排序后的半部分中创建一个新的排序列表。 – abarnert

+0

我在OP代码中的任何地方都看不到'a [index] = value',即a'部分是否作为副本传递并不重要,'a'也不会改变。 'local_a = whatever'对外界没有影响,除非它从函数返回。但OP忽略来自'mergesort()'< - 的返回值 - 这是真正的问题。 – jfs

+0

我想这是一个解释的问题。你的观点是,OP意在获得他的功能的返回值并使用它,但忘记了。他有回报声明支持这一点。我的观点是他期望这个变化发生在通过的阵列上。他试图做'a = auxa'的事实证明了这一点。根据你同意哪一个更多,这个问题要么是分片复制,要么是OP忽略了返回值,认为哪个是“真实的”对我没有太大的意义。 –

3

这就是我想出了:

from collections import deque 

def mergesort(array): 
    if len(array) <= 1: return array 

    midpoint = len(array)/2 

    left_array = deque(mergesort(array[:midpoint])) 
    right_array = deque(mergesort(array[midpoint:])) 

    merged_array = deque([]) 

    while len(left_array) and len(right_array): 
     if left_array[0] < right_array[0]: 
      merged_array.append(left_array.popleft()) 
     else: 
      merged_array.append(right_array.popleft()) 

    merged_array.extend(left_array) 
    merged_array.extend(right_array) 

    return merged_array 

print mergesort([3, 2, 1]) 
+1

'pop(0)'是列表中的“O(n)”,它使您的算法成为二次方,而不是通常的'O(n * log n)'用于mergesort。你可以尝试'collections.deque()'而不是'merged_array'列表。 '而left_array和right_array:'按原样工作。在第一个循环之后,“left_array”或“right_array”都是空的。你可以使用'merged_array.extend(left_array); merged_array.extend(right_array);'而不是最后两个循环。为了支持Python 3,你可以使用'//'(floor division)。 – jfs

+0

谢谢!我没有想到这一点。 –