合并排序以计算Python中的拆分反转

时间:2013-01-13 17:22:54

标签: python algorithm recursion mergesort

我正在尝试使用mergesort - 我得到 - 来计算列表中的拆分反转次数(也就是说,未排序列表的前半部分中的元素应该出现在第二个中的给定元素之后未排序列表的一半;例如[3 2 1 4]将包含拆分反转(3,1),但不包含(3,2),因为3和2都在前半部分中。当我得到最终的打印语句时,我得到了我期望的答案 - 在这种情况下为9 - 但是返回值都是因为它通过递归返回拆分值而非常糟糕。我已经尝试了各种索引组合无济于事。有帮助吗? (使用Python 2.7)

(为了记录,这是一个Coursera的家庭作业问题,但我只是为了好玩而学习 - 除了我之外,没有人对此进行评分。)

def mergesort(lst):
    '''Recursively divides list in halves to be sorted'''
    if len(lst) is 1:
        return lst
    middle = int(len(lst)/2)
    left  = mergesort(lst[:middle])
    right = mergesort(lst[middle:])
    sortedlist = merge(left, right)
    return sortedlist

def merge(left, right):
    '''Subroutine of mergesort to sort split lists.  Also returns number
    of split inversions (i.e., each occurence of a number from the sorted second
    half of the list appearing before a number from the sorted first half)'''
    i, j = 0, 0
    splits = 0
    result = []
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
            splits += len(left[i:])
    result += left[i:]
    result += right[j:]
    print result, splits
    return result, splits


print mergesort([7,2,6,4,5,1,3,8])

3 个答案:

答案 0 :(得分:3)

修改mergesort功能以忽略中间分割。

def mergesort(lst):
    '''Recursively divides list in halves to be sorted'''
    if len(lst) == 1:
        return lst, 0
    middle = len(lst)/2
    left = mergesort(lst[:middle])[0]  # Ignore intermediate splits
    right = mergesort(lst[middle:])[0]  # Ignore intermediate splits
    sortedlist, splits = merge(left, right)
    return sortedlist, splits

答案 1 :(得分:2)

您的代码中存在一些问题:

  • 不要int() len() / 2的结果。如果您使用的是Python3,我会直接使用整数除法与//运算符。
  • mergesort()第一行的比较是错误的。首先,不要使用is来比较相等性。 is运算符仅用于标识。如果您有两个具有相同值的不同整数,则它们相等但不相同。对于小整数,我相信至少有一些Python方言会实现这个值,因此你的比较有效,但你依赖的是一些不能保证的东西。尽管如此,使用==也不起作用,因为你忘记了空列表的情况。
  • 我猜你的实际问题(“不稳定的返回值”)是由于你在一个名称下返回两个存储(作为元组)的值,然后作为参数传递给递归{{1} }来电。

答案 2 :(得分:0)

因为,在你的代码合并中返回一对,mergesort也必须返回一对。 启用以在列表中获得总分割反转,您必须添加左半部分,右半部分并合并分割反转。

以下是我在您的代码中所做的修改。

def mergesort(lst):
    '''Recursively divides list in halves to be sorted'''
    if len(lst) == 1:
        return lst, 0
    middle = len(lst)/2
    left, s1 = mergesort(lst[:middle])[0]  # Ignore intermediate splits
    right, s2 = mergesort(lst[middle:])[0]  # Ignore intermediate splits
    sortedlist, s3 = merge(left, right)
    return sortedlist, (s1+s2+s3)`