Mergesort implementation in Python

独自空忆成欢 提交于 2019-12-13 01:29:10

问题


I've been implementing a mergesort (from interactivepython) in Python/C++. The code fully works, but my issue is that I can't seem to figure out why a particular portion of the code actually does work.

Code is:

def mergeSort(alist):
    if len(alist)>1:
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]

        mergeSort(lefthalf)
        mergeSort(righthalf)

        i=0
        j=0
        k=0
        while i<len(lefthalf) and j<len(righthalf):
            if lefthalf[i]<righthalf[j]:
                alist[k]=lefthalf[i]
                i=i+1
            else:
                alist[k]=righthalf[j]
                j=j+1
            k=k+1

        while i<len(lefthalf):
            alist[k]=lefthalf[i]
            i=i+1
            k=k+1

        while j<len(righthalf):
            alist[k]=righthalf[j]
            j=j+1
            k=k+1

plist = [54,26,93,17]
mergeSort(plist)
print(plist)

After lefthalf = [54 26], the further subroutine split to lefthalf = [54] and righthalf = [26], the merge code works to provide alist = [26, 54] (which is the sorted left half).

Now the next step that I do in the debug window, I get a lefthalf = [26, 54]. How is this possible, as the first debug shows it defined as [54, 26] before. Where does the update to [26, 54] happen?

Any help would be super appreciated!


回答1:


Lists in python are mutable (ie, their contents can change) inside functions. When the list is changed inside the function, the change happens to the list that you called the function with, because it is the same list.

Therefore, the update to your list, happens every time something manipulates alist or a slice of alist, either in the first call or in any of the recursive calls.

Edit: removed misleading bit




回答2:


Your mergesort function modifies the list you pass to it in place. That is, it changes the contents so that the items are in order, rather than returning a new list.

This is what you're seeing in your debugger, during the recursive calls. In the first level of the recursion, lefthalf is created by copying some values from the original list (with slice syntax). It starts out containing [54, 26]. This list is then passed to another call of mergesort. Note that the naming can get confusing, as in the inner call it refers to the list as alist (and it has its own separate lefthalf list). When the inner call returns, the contents of the outer call's lefthalf turn out to have been modified to [26, 54] (they're in order, which is what we want!).

It may be that your debugger isn't making it clear when the return is happening. Since it's all the same function (due to the recursion), it may not be obvious when the inner call ends and the control flow of the outer call resumes.

Here's a walkthrough of your code in which I show the the values of the the different variables in the various levels of the recursion as you sort your example list. Note that this isn't runnable Python code, I'm indenting to indicate the level of recursion, not for control flow. To keep the example relatively short, I'm also leaving out some steps such as as comparing the values from the two sublists and updating the i j and k indexes during the merge process:

plist = [54,26,93,17]
mergesort(plist)
    # alist is a referece to plist which contains [54,26,93,17]
    lefthalf = alist[:mid]  # new list which initially contains [54,26]
    righthalf = alist[mid:] # new list which initially contains [93,17]
    mergesort(lefthalf)
        # alist is a reference to the outer lefthalf list, which contains [54,26]
        lefthalf = alist[:mid]  # new list, initially contains [54]
        righthalf = alist[mid:] # new list, initially contains [26]
        mergesort(lefthalf)
            # alist is a reference to the previous level's lefthalf, [54]
            # the if statement doesn't pass its test, so we do nothing here (base case)
        # lefthalf was not changed by the recursive call
        mergesort(righthalf)
            # alist is a reference to the previous level's righthalf, [26]
            # base case again
        # righthalf was not changed
        alist[k]=righthalf[j] # now we merge lefthalf and righthalf back into alist
        alist[k]=lefthalf[i] # these statements change the contents of alist
    # lefthalf's contents changed, it is now sorted, [26,54]
    mergesort(righthalf)
        # alist is a reference to the outer righthalf list, which contains [93,17]
        lefthalf = alist[:mid]  # new list, initially contains [93]
        righthalf = alist[mid:] # new list, initially contains [17]
        mergesort(lefthalf) # base case, nothing happens (I'll skip the details)
        mergesort(righthalf) # base case, nothing happens
        alist[k]=righthalf[j] # merge lefthalf and righthalf back into alist
        alist[k]=lefthalf[i]  # we change the contents of alist to [17,93]
    # righthalf's contents changed, it is now sorted, [17,93]
    alist[k]=righthalf[j] # merge lefthalf and righthalf back into alist (more steps)
    alist[k]=lefthalf[i]
    alist[k]=lefthalf[i]
    alist[k]=righthalf[j] # after these statements, alist is [17,26,54,93]
# plists's contents are changed so it contains [17,26,54,93]

It might help you to step back a bit from this complex recursive situation and look at a simpler example to make sure you understand how lists can be mutated:

a = [1, 2] # create a list object with some initial contents

b = a      # b refers to the same list object as a, nothing is copied
b[1] = 3   # this modifies the list object itself, replacing the 2 with a 3

print(a)   # prints [1, 3] even through we're looking at a rather than b

def func(lst): # lst will be a new name bound to whatever is passed to the function
    lst[1] = 4 # we can modify that passed-in object (assuming it's the right type)

func(a)    # lst in the function will become another name for the list object
print(a)   # prints [1, 4]


来源:https://stackoverflow.com/questions/31575482/mergesort-implementation-in-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!