简体   繁体   English

无法跟踪我的合并排序算法(Python 3)

[英]Trouble tracing my Merge sort algorithm (Python 3)

I wrote a short Merge sort algorithm in Python 3. I have trouble understanding how it manages to achieve the correct result, as when I try to trace its logical steps I end up with an out of order list.我在 Python 3 中编写了一个简短的合并排序算法。我很难理解它是如何实现正确结果的,因为当我尝试跟踪它的逻辑步骤时,我最终得到了一个乱序列表。 The annotated code can be seen below.注释代码如下所示。

What I'm specifically referring to is the merging part of the code.我具体指的是代码的合并部分。 The three 'while' loops.三个“while”循环。

Let me use an example to demonstrate what confuses me.让我用一个例子来说明什么让我感到困惑。 I explain the details in the annotations.我在注释中解释了细节。

Thank you in advance for your time and help.提前感谢您的时间和帮助。

Let's assume we want to merge two arrays.假设我们要合并两个 arrays。

left = [2,6]
right = [4,8]

def merge_sort(array):

    if len(array) > 1:

        middle = len(array)//2

        left = array[:middle]
        right = array[middle:]

        merge_sort(left)
        merge_sort(right)

        i = j = k = 0

        while i < len(left) and j < len(right):

            # i.e. if 2 < 4
            if left[i] < right[j]: 

                # The first index of the array is assigned the value 2
                array[k] = left[i]  

                # i = 1 now
                i += 1

            # The 'else' statement is not executed, because the 'if' statement was.
            else:

                array[k] = right[j]
                j += 1

            # k = 1 now
            k += 1 

        # The 'while' loop below assigns '6' as the value for index 1 of the array and terminates.
        # k = 2 now
        while i < len(left):
       
            array[k] = left[i]
            i += 1
            k += 1

        # The last 'while' loop assigns '4' and '8' to indexes 2 and 3 of the array, respectively.
        while j < len(right):

            array[k] = right[j]
            j += 1
            k += 1

        # The algorithm terminates and from what I can see I should end up with the array of [2,6,4,8].
        # I do not, however. It is sorted in ascending order and I cannot see where I'm making a mistake.

Firstly, careful with your wording, to be clear merge sort isn't merging distinct arrays, merge sort cleverly deconstructs a single unsorted array into sub-arrarys (in our case left and right) and sorts them individually and merges them back into a single array again with a final sort.首先,请注意您的措辞,要明确合并排序不会合并不同的 arrays,合并排序巧妙地将单个未排序的数组解构为子数组(在我们的例子中为左右)并将它们单独排序并将它们合并回单个再次进行最终排序的数组。 In other words, you pass this function a single array unsorted and it returns a single sorted array.换句话说,您将这个 function 传递给一个未排序的单个数组,它会返回一个已排序的数组。 If you need to merge two arrays, you would do so before calling it.如果你需要合并两个 arrays,你会在调用它之前这样做。

Merge Sort合并排序

"Merge sort is a recursive algorithm that continually splits a list in half. If the list is empty or has one item, it is sorted by definition (the base case). If the list has more than one item, we split the list and recursively invoke a merge sort on both halves. Once the two halves are sorted, the fundamental operation, called a merge, is performed. Merging is the process of taking two smaller sorted lists and combining them together into a single, sorted, new list." “合并排序是一种递归算法,它不断将列表分成两半。如果列表为空或有一项,则按定义排序(基本情况)。如果列表有多个项目,我们将列表拆分并递归地在两半上调用合并排序。一旦两半排序完毕,就会执行称为合并的基本操作。合并是获取两个较小的排序列表并将它们组合成一个单独的排序新列表的过程。 "

Debug/Analyze Code调试/分析代码

To help with understanding how it works (and debug), inject print comments at the very least to best show what is going on in more detail.为了帮助理解它的工作原理(和调试),至少注入打印注释以最好地更详细地显示正在发生的事情。 I have taken what you wrote and added print comments and pass the function a string to help determine which array (left or right) it is sorting.我已经接受了您编写的内容并添加了打印注释,并向 function 传递了一个字符串,以帮助确定它正在排序的数组(左或右)。 You can see the splitting sorting, and merging as it accomplishes the sort by splitting the array down to size one and merging the sorted sub arrays etc. in the process...您可以看到拆分排序和合并,因为它通过将数组拆分为大小为一并在此过程中合并排序的子 arrays 等来完成排序...

def merge_sort(array,type):
    print('merge_sort =>' + type)
    if len(array) < 2:
        print('Array < 2 nothing changed')
        return array
    middle = len(array) // 2
    left = array[:middle]
    right = array[middle:]
    print('splitting : ' + str(array))
    merge_sort(left,'left')
    merge_sort(right,'right')
    i = j = k = 0
    print('sorting.. Left/Right:' + str(left) + str(right))
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            print(' - left[i] < right[j] ('+ str(left[i]) + ' < ' + str(right[j]) + ') set array[' + str(k) + '] = ' + str(left[i]) + '')
            array[k] = left[i]
            i += 1
        else:
            print(' - else left[i] >= right[j] ('+ str(left[i]) + ' >= ' + str(right[j]) + ') set array[' + str(k) + '] = ' + str(right[j]) + '')
            array[k] = right[j]
            j += 1
        k += 1
    while i < len(left):
        print(' - WHILE i < len(left), ('+str(i) +' < '+str(len(left))+'), set array[' + str(k) + '] = ' + str(left[i]) + '')
        array[k] = left[i]
        i += 1
        k += 1
    while j < len(right):
        print(' - while j < len(right) ('+str(j) +' < ' + str(len(right)) + '), set array[' + str(k) + '] = ' + str(right[j]) + '')
        array[k] = right[j]
        j += 1
        k += 1
    print("returning.." + str(array))
    return array

arr = [2,6,4,8]
result = merge_sort(arr,'full')
print(result)

Which provides the following output:其中提供以下output:

merge_sort =>full
splitting : [2, 6, 4, 8]
merge_sort =>left
splitting : [2, 6]
merge_sort =>left
Array < 2 nothing changed
merge_sort =>right
Array < 2 nothing changed
sorting.. Left/Right:[2][6]
 - left[i] < right[j] (2 < 6) set array[0] = 2
 - while j < len(right) (0 < 1), set array[1] = 6
returning..[2, 6]
merge_sort =>right
splitting : [4, 8]
merge_sort =>left
Array < 2 nothing changed
merge_sort =>right
Array < 2 nothing changed
sorting.. Left/Right:[4][8]
 - left[i] < right[j] (4 < 8) set array[0] = 4
 - while j < len(right) (0 < 1), set array[1] = 8
returning..[4, 8]
sorting.. Left/Right:[2, 6][4, 8]
 - left[i] < right[j] (2 < 4) set array[0] = 2
 - else left[i] >= right[j] (6 >= 4) set array[1] = 4
 - left[i] < right[j] (6 < 8) set array[2] = 6
 - while j < len(right) (1 < 2), set array[3] = 8
returning..[2, 4, 6, 8]

This yields something apx.这会产生一些东西。 like so:像这样: 在此处输入图像描述

References: How do I merge arrays in python?参考: 如何在 python 中合并 arrays? https://runestone.academy/runestone/books/published/pythonds/SortSearch/TheMergeSort.html https://runestone.academy/runestone/books/published/pythonds/SortSearch/TheMergeSort.html

It seems in your annotations you exit the first while loop prematurely, you stop after one run when the code actually does 3 runs.在您的注释中,您似乎过早地退出了第一个while循环,当代码实际运行 3 次时,您在一次运行后停止。 Here is how you would follow wgat actually happens:以下是您将如何关注 wgat 实际发生的情况:

  • you run through it once, then you have k=1 , i=1 and j=0 ,你通过它一次,然后你有k=1i=1j=0
  • so you go through this loop again (this time it is the else that is executed, and assigns 4 to index 1 of the array, now k=2 , i=1 and j=1所以你 go 再次通过这个循环(这次是else被执行,并将 4 分配给数组的索引 1,现在k=2i=1j=1
  • so you run through the loop a third time, with thte if executed, finally k=3 , i=2 and j=1 , so you get out of the first while .所以你第三次运行循环, if执行,最后是k=3i=2j=1 ,所以你退出第一个while

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM