【问题标题】:a bug of merge sort using Python使用 Python 进行合并排序的错误
【发布时间】:2016-06-16 01:09:33
【问题描述】:

我正在使用递归 Python 进行合并排序。 我找不到我在哪里犯了错误并且总是得到错误的答案。 代码如下:

def mergeSort(xlist):
    print ('Splitting',xlist, len(xlist))
    if len(xlist)>1:
       midpoint = len(xlist) // 2
       left  = xlist[:midpoint]
       right = xlist[midpoint:]
       print ('----------------------------')
       mergeSort(left)
       mergeSort(right)

       print (left, 'r', right)

       while len(right) >0:
          left.append(right[0])
          right.remove(right[0])
          slot= len(left)-1
          while slot >0:
              if left[slot] < left[slot-1]: left[slot], left[slot-1] = left[slot-1], left[slot]
              slot -= 1

       print ('sorted',left, right,xlist)
       return left

print('A',mergeSort([100,1,91,54])) 

合并时,输出也显示错误,如:

 Splitting [100, 1, 91, 54] 
 ---------------------------- 
 Splitting [100, 1] 2
 ---------------------------- 
 Splitting [100] 1 
 Splitting [1] 1 
 [100] r [1] 
 sorted [1, 100] [] [100, 1]
 Splitting [91, 54] 2
 ---------------------------- 
 Splitting [91] 1 
 Splitting [54] 1 
 [91] r [54] 
 sorted [54, 91] [] [91, 54]
 [100, 1] r [91, 54] 
 sorted [1, 54, 100, 91] [] [100, 1, 91, 54]
 A [1, 54, 100, 91]

我希望返回后的最后第三行应该是“[1,100] r [54, 91]”。 这里有什么问题?我知道interactivePython.org 中有一段代码,但我想了解我在哪里犯了逻辑错误。谁能帮我?非常感谢!

【问题讨论】:

  • 如果 len(xlist)&gt;1 不为真,该函数什么也不做,因此它返回 None。这是故意的吗?
  • 您的代码的后半部分并没有真正进行合并排序。附加到left 不是合并 - 它依赖于您的清理代码以sloooowly 以正确的顺序排列列表。您已经以合并排序的名义有效地实现了 shell 排序

标签: python sorting recursion merge


【解决方案1】:

您需要决定您的mergesort 代码是要修改它传递的列表,还是要返回一个新列表。编写代码的顶部就好像它将修改列表一样。下半部分的写法好像它返回一个新列表。它们都需要以相同的方式工作,否则排序将不起作用。

如果你想坚持使用就地修改的方法,代码的顶部没问题,你需要修复的只是最后合并leftright。您需要合并到xlist,而不是合并到left。我建议在这三个列表中的每一个中使用单独的索引,而不是像您目前正在做的那样对 left 进行昂贵的插入。

如果要返回新列表,则需要更改代码的顶部。如果您遇到基本情况 (len(xlist) &lt; 2),则需要返回 xlist 未修改。您还需要保存递归调用的返回值,可能使用left = mergesort(left)right = mergesort(right)。您以后的合并代码可能没问题,尽管它放弃了合并排序的大部分性能优势,因为插入逻辑是O(N**2)

【讨论】:

  • 我实际上已经尝试将我的代码修改为在“print ('sorted',left,right,xlist)”之前添加“xlist = left”并删除“return left”。这是就地修改的方法,但它仍然不起作用。
  • xlist = left 不会修改xlist 指向的列表,它只是重新绑定名称。您可以使用xlist[:] = left,但最好将leftright 中的值直接合并到xlist 中(您当前的合并过程非常低效)。
  • 谢谢!现在可以了。 xlist =left 和 xlist[:] = left 有什么区别?也感谢您提醒我当前的合并过程根本没有效率。
  • xlist = left 重新绑定名称 xlist 以引用与 left 相同的对象。另一方面,使用切片赋值会修改现有xlist 对象的内容,因此它仍然引用同一个对象,但内容不同。
【解决方案2】:

我花了几分钟,但我找到了。您正确地重复左右两半,但随后您丢弃结果并合并原始列表。更正:

    print ('----------------------------')
    left  = mergeSort(left)
    right = mergeSort(right)

我希望您现在可以看到效果。


这是产生上述输出的工作代码:

def mergeSort(xlist):
    print 'Splitting', xlist, len(xlist)
    if len(xlist) <= 1:
        return xlist
    else:
        midpoint = len(xlist) // 2
        left  = xlist[:midpoint]
        right = xlist[midpoint:]
        print ('----------------------------')
        left  = mergeSort(left)
        right = mergeSort(right)

        print left, 'r', right

        # print "merge", left, right
        while len(right) > 0:
            left.append(right[0])
            right.remove(right[0])
            slot = len(left) - 1
            while slot > 0:
                if left[slot] < left[slot-1]:
                    left[slot], left[slot-1] = left[slot-1], left[slot]
                # print "switched", left
                slot -= 1

        print 'sorted', left, right, xlist
        return left

print 'A',mergeSort([100,1,91,54])

输出:

A Splitting [100, 1, 91, 54] 4
----------------------------
Splitting [100, 1] 2
----------------------------
Splitting [100] 1
Splitting [1] 1
[100] r [1]
sorted [1, 100] [] [100, 1]
Splitting [91, 54] 2
----------------------------
Splitting [91] 1
Splitting [54] 1
[91] r [54]
sorted [54, 91] [] [91, 54]
[1, 100] r [54, 91]
sorted [1, 54, 91, 100] [] [100, 1, 91, 54]
[1, 54, 91, 100]

【讨论】:

  • 谢谢!但实际上我已经尝试按照您建议的方式进行操作,它显示以下错误消息(我使用了 ipython):..... in mergeSort(xlist) 12 print (left, 'r ', right) 13 ---> 14 while len(right) >0: 15 left.append(right[0]) 16 right.remove(right[0]) TypeError: 'NoneType' 类型的对象没有 len( )
猜你喜欢
  • 2016-01-06
  • 2017-04-28
  • 1970-01-01
  • 2021-11-25
  • 2011-04-01
  • 2022-01-10
  • 2018-10-16
  • 2021-07-14
  • 2014-01-14
相关资源
最近更新 更多