【问题标题】:Mergesort code hangs合并排序代码挂起
【发布时间】:2018-05-09 06:02:55
【问题描述】:

我正在尝试实现归并排序。我有一个适用于排序列表的工作合并子功能,只需要正确管理所有列表的合并。

def mergesort(alist):
    alist = [[i] for i in alist]

    def merge(clist, dlist): #assume inputs are sorted
        merged = []
        while True:
            if len(clist) == 0:
                return merged + dlist
            elif len(dlist) == 0:
                return merged + clist
            elif clist[0] < dlist[0]:
                merged.append(clist[0])
                del clist[0]
            elif clist[0] > dlist[0]:
                merged.append(dlist[0])
                del dlist[0]            
        return merged

    while True:
        if len(alist) % 2 == 0 and len(alist) > 2:
            alist = [merge(alist[2*i], alist[2 * i + 1]) for i in range(int(len(alist)/2))]
        elif len(alist) == 2:
            print('ayyy')
            alist = merge(alist[0], alist[-1])
            return alist
        elif len(alist) % 2 == 1 and len(alist) > 1:
            tag = alist[-1]
            del alist[-1]
            alist = [merge(alist[2 * i], alist[2 * i + 1]) for i in range(int(len(alist)/2))]
            alist.append(tag)
        else:
            return alist


print(mergesort([10, 5, 8, 16, 258, 11, 1, 20, 489, 10, 5, 3, 12]))

该函数工作正常,直到它下降到最后两个列表。它打印“ayyy”,这意味着它进入了第一个 elif 语句,然后什么都不做。该程序不会终止,它只是旋转它的轮子。调试器显示alist 的值也没有更新。

【问题讨论】:

  • 你有相同的元素(5 & 5)。内部合并函数无法处理它们,因此永远循环。

标签: python mergesort


【解决方案1】:

您只有一个小错误,因为您没有处理 merge 中的相等元素。这是一个小修复:

if len(clist)==0:
    return merged+dlist
elif len(dlist)==0:
    return merged+clist
elif clist[0]<dlist[0]:
    merged.append(clist[0])
    del clist[0]
elif clist[0]>dlist[0]:
    merged.append(dlist[0])
    del dlist[0]
else: # clist[0]==dlist[0]
    merged.append(clist[0])
    merged.append(dlist[0])
    del clist[0]
    del dlist[0]

【讨论】:

  • 在最后一个 elif 语句中将 '>' 更改为 '>=' 是否也有效?一种方法更好吗?
  • @kubleeka 你可以这样做,但我的方法会节省一个周期。但除此之外,方法还可以。
  • 可能存在相同但不同的项目(例如,优先级)。在这种情况下,此版本执行zipper merge,而&lt;=&gt;= 更愿意用尽一个特定列表。
【解决方案2】:

我无法抗拒使用迭代器重写merge 的诱惑,这种方式不会改变参数列表。

def merge(clist, dlist):
    "Merges two sorted lists into one still sorted list"
    if not clist:      # Trivial empty cases
        return dlist
    if not dlist:
        return clist
    cs = iter(clist)   # Iterators produce each item only once
    ds = iter(dlist)
    c = next(cs)
    d = next(ds)
    result = []
    while True:
        if c <= d:
            result.append(c)
            try:
                c = next(cs)
            except StopIteration:  # exhausted c before d
                result.append(d)
                result.extend(ds)
                return result
        else:  # c > d
            result.append(d)
            try:
                d = next(ds)
            except StopIteration:
                result.append(c)
                result.extend(cs)
                return result

显然,这可以通过平等对待列表来统一。这个特定版本更喜欢首先放置第一个列表中的项目。

注意del somelist[0]是最昂贵的项目删除操作;它移动除第一个之外的所有条目。 deques 支持更高效的 p​​opleft 方法(但在创建许多小实例时成本更高,而合并排序确实如此)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    • 2016-02-06
    • 1970-01-01
    • 2013-09-27
    相关资源
    最近更新 更多