【问题标题】:How can I count the swaps in a Merge Sort Algorithm in Python [duplicate]如何计算 Python 合并排序算法中的交换次数 [重复]
【发布时间】:2017-12-31 10:17:41
【问题描述】:

我已经完成了 MergeSort 算法,但我不知道如何计算交换次数。

我的代码是:

def mergesortInv(list):
    if len(list) < 2:
        return list
    else:
        middle = len(list) // 2
        left = mergesortInv(list[:middle])   #definim les dues meitats
        right = mergesortInv(list[middle:])
        swaps=???       
    return mergeInv(left, right,swaps)

def mergeInv(left, right,swaps):
    if len(left) < 1:
        return right
    if len(right) < 1:
        return left
    if left[0] <= right[0]:
        return [left[0]] + mergeInv(left[1:],right,swaps)
    else:
        return [right[0]] + mergeInv(left,right[1:],swaps)

该算法的输出将是排序列表(该算法在这部分工作)和交换次数:mergesortInv(list) == ([1, 2, 3, 4, 5, 7, 8], 6) 6 是交换次数。

【问题讨论】:

  • 交换发生在mergeInv 方法的else 部分内。如果您每次到达那里时都增加一个索引,那应该代表最后的总掉期。但是您可能必须更改建议的函数签名。要么保留一个全局索引(坏),要么返回每个 mergeInvcall 中的交换次数并累积它们(好)。
  • 请参阅Counting inversions in an array。那里的答案显示了如何使用归并排序来计算反转,但还有其他方法可以做到这一点。请查看我的答案,该答案比较了不同列表大小上各种算法的速度。
  • @Anubis 我会试试你给我的最后一个选项
  • 顺便说一句,使用list 作为变量名不是一个好主意,因为这会影响内置的list 类型。它不会在这里造成任何伤害,但它会使阅读您的代码有点混乱。如果出于某种原因您尝试在 mergesortInv 中使用 list 来创建列表,您会收到一条神秘的错误消息。
  • 我使用了list,因为它是一个中性名称,但在我原来的算法中我有另一个名称。

标签: python mergesort


【解决方案1】:

这里是您的代码的稍微修改的版本,似乎可以工作:

def mergesortInv(list, mergeInv):
    if len(list) < 2:
        return list, 0
    else:
        middle = len(list) // 2
        left, lc = mergesortInv(list[:middle], mergeInv)   #definim les dues meitats
        right, rc = mergesortInv(list[middle:], mergeInv)
    merge, mc = mergeInv(left, right)
    return merge, lc + rc + mc

def mergeInvRec(left, right):
    if len(left) < 1:
        return right, 0
    if len(right) < 1:
        return left, 0
    if left[0] <= right[0]:
        res, cnt = mergeInvRec(left[1:], right)
        return [left[0]] + res, cnt
    else:
        res, cnt = mergeInvRec(left, right[1:])
        return [right[0]] + res, len(left) + cnt

def mergeInvFlat(left, right):
    res, cnt = [], 0
    il, ir = 0, 0
    nl, nr = len(left), len(right)
    while il < nl and ir < nr:
        if left[il] <= right[ir]:
            res.append(left[il])
            il += 1
        else:
            res.append(right[ir])
            ir += 1
            cnt += nl - il
    res.extend(left[il:])
    res.extend(right[ir:])
    return res, cnt

这主要是簿记问题。计算每一步的交换次数并添加它们。在最后一个分支中,right 的第一个元素一直冒泡,一直经过 left 的每个元素,这就是为什么我们计数 len(left) 在那里交换。

编辑: 正如@PM2Ring 指出的那样,mergeInv 中的递归有点鲁莽,对于中等大小的列表,它将超过 Python 的最大递归深度。 我添加了一个非递归版本。您可以通过将它们的名称作为第二个参数传递给主函数来在递归和非递归版本之间切换。

【讨论】:

  • 好的,我已经抓到了
  • @ZRTSTR 请注意,在包含大约 1000 个或更多项目的列表上,此代码将失败并显示 RecursionError: maximum recursion depth exceeded in comparison
  • @PM2Ring 不错。会更新。
  • 好多了!而且速度也快了很多。在我的 timeit 测试中,当列表大小超过 40 左右时,它现在比大多数其他基于合并排序的版本都快。
  • @PM2Ring 刚刚查看了您的链接答案。印象深刻。你似乎对这个话题很感兴趣;-]
【解决方案2】:

我没有对此进行测试,但这只是为了让您了解我在对您的问题的评论中提出的建议。

def mergesortInv(list):
    if len(list) < 2:
        return list
    else:
        middle = len(list) // 2
        left = mergesortInv(list[:middle])   #definim les dues meitats
        right = mergesortInv(list[middle:])
        # swaps=???
    return mergeInv(left, right)

def mergeInv(left, right):
    """ return a tuple of total swaps and the merged list """
    if len(left) < 1:
        return (0, right)
    if len(right) < 1:
        return (0, left)
    if left[0] <= right[0]:
        swaps, lst = mergeInv(left[1:],right)
        return (swaps, [left[0]] + [lst])
    else:
        swaps, lst = mergeInv(left,right[1:])
        return (swaps + 1, [right[0]] + [lst])

用法,

swaps, lst = mergesortInv(mylist)

【讨论】:

  • 这不起作用。 mergeInv 返回一个元组,mergesortInv 也是如此,但在 mergesortInv 内部有 left = mergesortInv(list[:middle])right = mergesortInv(list[middle:]),所以 leftright 都获得分配给它们的元组。此外,在mergeInv 中,您可以使用[left[0]] + [lst][right[0]] + [lst] 创建嵌套列表。
  • 顺便说一句,元组是由逗号构成的,而不是括号,括号仅在某些情况下需要以防止歧义。所以你可以这样做,例如return 0, right
猜你喜欢
  • 2018-05-30
  • 1970-01-01
  • 2021-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-27
相关资源
最近更新 更多