在python中实现mergesort算法变体的索引超出范围?

时间:2015-10-19 14:25:08

标签: python algorithm sorting recursion mergesort

我根据我从CLRS书中学到的内容,在python中完成了我的合并排序算法的变体,并将其与麻省理工学院的入门计算机科学书中的实现进行了比较。我在算法中找不到问题,IDLE给了我一个超出范围的索引,虽然一切看起来都不错。我不确定这是否是由于从麻省理工学院算法中借鉴思路时出现的一些混乱(见下文)。

lista = [1,2,3,1,1,1,1,6,7,12,2,7,7,67,4,7,9,6,6,3,1,14,4]   

def merge(A, p, q, r):
    q = (p+r)/2
    L = A[p:q+1]
    R = A[q+1:r]

    i = 0
    j = 0

    for k in range(len(A)):

        #if the list R runs of of space and L[i] has nothing to compare
        if i+1 > len(R):
            A[k] = L[i]
            i += 1

        elif j+1 > len(L):
            A[k] = R[j]
            j += 1

        elif L[i] <= R[j]:
            A[k] = L[i]
            i += 1

        elif R[j] <= L[i]:
            A[k] = R[j]
            j += 1

        #when both the sub arrays have run out and all the ifs and elifs done,
        # the for loop has effectively ended

    return A


def mergesort(A, p, r):
    """A is the list, p is the first index and r is the last index for which
        the portion of the list is to be sorted."""
    q = (p+r)/2
    if p<r:
        mergesort(A, p, q)
        mergesort(A, q+1, r)
        merge (A, p, q, r)
    return A

print mergesort(lista, 0, len(lista)-1)

我尽可能地遵循CLRS中的伪代码,只是没有使用&#34;无穷大值&#34;在L和R的末尾,这将继续比较(这效率会降低吗?)。我试图在麻省理工学院的书中加入这样的想法,即简单地将剩下的L或R列表复制到A,改变A并返回一个排序列表。但是,我似乎无法找到它出了什么问题。另外,我不知道为什么伪代码需要一个&#39; q&#39;作为输入,假设q无论如何都将被计算为中间索引的(p + q)/ 2。为什么需要把p

另一方面,从麻省理工学院的书中,我们看起来非常优雅。

def merge(left, right, compare):
    """Assumes left and right are sorted lists and
compare defines an ordering on the elements.
Returns a new sorted(by compare) list containing the
same elements as(left + right) would contain.
"""
    result = []
    i, j = 0, 0

    while i < len(left) and j < len(right):
        if compare(left[i], right[j]):
            result.append(left[i])
            i += 1
        else :
            result.append(right[j])
            j += 1

    while (i < len(left)):
        result.append(left[i])
        i += 1

    while (j < len(right)):
        result.append(right[j])
        j += 1

    return result

import operator

def mergeSort(L, compare = operator.lt):
    """Assumes L is a list, compare defines an ordering
on elements of L. 
Returns a new sorted list containing the same elements as L"""
if len(L) < 2:
    return L[: ]
else :
    middle = len(L) //2
left = mergeSort(L[: middle], compare)
right = mergeSort(L[middle: ], compare)
return merge(left, right, compare)

我哪里可能出错?

另外,我认为MIT实现的主要区别在于它创建了一个新列表而不是改变原始列表。这让我很难理解mergesort,因为我发现CLRS的解释非常清楚,通过对不同的递归层理解它,以便对原始列表中最微小的组件进行排序(长度为1的列表不需要排序),因此&#34;存储&#34;旧列表本身内的递归结果。

然而,再想一想,说&#34;结果&#34;是否正确?由麻省理工学院算法中的每次递归返回,而后者又合并了?

谢谢!

1 个答案:

答案 0 :(得分:1)

代码和MIT之间的根本区别在于mergesort函数中的条件语句。你的if语句是:

if p<r:

他们是:

if len(L) < 2:

这意味着如果你在递归调用树的任何一点都有一个len(A) == 1的列表,那么它仍会在1或甚至0的列表上调用merge 。您可以看到这会导致合并函数出现问题,因为您的LR或两个子列表最终可能大小为0,这将导致out if ifs索引错误。 / p>

然后可以通过将if语句更改为与他们相似的内容(例如len(A) < 2r-p < 2

)来轻松解决您的问题