I know how Merge Sort works, but How Merge Sort Code Works?

旧巷老猫 提交于 2021-01-29 02:30:31

问题


You can read this on Wikipedia:

function merge_sort(list m)
// Base case. A list of zero or one elements is sorted, by definition.
if length(m) <= 1
    return m

// Recursive case. First, *divide* the list into equal-sized sublists.
var list left, right
var integer middle = length(m) / 2
for each x in m before middle
     add x to left
for each x in m after or equal middle
     add x to right

// Recursively sort both sublists
left = merge_sort(left)
right = merge_sort(right)

// Then merge the now-sorted sublists.
return merge(left, right)

On line 1 there's a list of numbers, let's say 9 6 3 7 5 1 8 2

They say that merge_sort divides the list on 2 and 2 again and again until each list has only 1 integer left, like this one:

9 6 3 7 5 1 8 2 -->
9 6 3 7 - 5 1 8 2 -->
9 6 - 3 7 - 5 1 - 8 2 -->
9 - 6 - 3 - 7 - 5 - 1 - 8 - 2

And then the numbers are put together like this:

6 9 - 3 7 - 1 5 - 2 8 -->
3 6 7 9 - 1 2 5 8 -->
1 2 3 5 6 7 8 9 -->

But I don't see where in the code the list of integers are divided on 2 again and again until each has only 1 integer left?

var list left, right
var integer middle = length(m) / 2
for each x in m before middle
     add x to left
for each x in m after or equal middle
     add x to right

As I understand, on the code above, the list of numbers is divided to two different lists: 9 6 3 7 and 5 1 8 2

What then happens on the code below?

left = merge_sort(left)
right = merge_sort(right)

Can someone explain me how the merge_sort code above exactly works step by step?


回答1:


But I don't see where in the code the list of integers are divided on 2 again and again until each has only 1 integer left?

var list left, right
var integer middle = length(m) / 2          --------statement-1
for each x in m before middle               --------statement-2
   add x to left
for each x in m after or equal middle       --------statement-3
   add x to right

At the statement-1 you divide the array into two parts and add them to the left and right sub-array. In the statement-2, you are adding all the element before middle, which is your middle element of the array. Similarly statement-3, you are adding rest of the element in right sub-array. So essentially, you keep on dividing the array in two parts until their size is 1 or 0.

if length(m) <= 1
    return m

In the start you have above conditional check, which return the method call if the size of the array is less then or equal to one.

What then happens on the code below?

left = merge_sort(left)
right = merge_sort(right)

This is a recursive call to sort (divide the array until size is one) the each sub array. Which is created in the above pseudo-code. You sort left and right sub-array separately and then join them into a single array.

return merge(left, right)

Here both left and right sub-array are passed to a merge function. These both array are sorted array. The task of the merge function is merge these sub-array into a single sorted array.




回答2:


The pseudo code is missing some details. There was debate on the talk page about removing it or fixing it. Note it's supposed to be working with a list, not an array, which is why elements can only be appended one at a time. The list is not really split into 2 parts; instead two new initially empty lists left and right are created, then (middle = length/2) elements are moved from list to left, then (length - middle) elements are moved from list to right. This cleaned up example with C++ comments may make more sense, but it's still an inefficient way to sort a list. A bottom up merge sort using an array of pointers is much more efficient. I can add example code here if anyone is interested.

var list left, right
var integer middle = length(m) / 2
var integer count
for (count = 0; count < middle; count += 1)
     get x from front of list        // x = *list.front()
     remove first element from list  // list.pop_front()
     add x to left                   // left.push_back(x)
for (count = middle; count < length; count += 1)
     get x from front of list        // x = *list.front()
     remove first element from list  // list.pop_front()
     add x to right                  // right.push_back(x)

In that same wiki article, there are two C / C++ like code examples, which should be easier to understand. The examples are simplified and copy data back to the original array after each merge step, which could be avoided with more optimized code.

http://en.wikipedia.org/wiki/Merge_sort#Top-down_implementation

http://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation

The sequence is different for top down merge sort, it's depth first, left first:

9 6 3 7 5 1 8 2
9 6 3 7|5 1 8 2
9 6|3 7
9|6
6 9
    3|7
    3 7
3 6 7 9
        5 1|8 2
        5|1
        1 5
            8|2
            2 8
        1 2 5 8
1 2 3 5 6 7 8 9

Bottom up merge sort skips the recursion and just starts off assuming a run size of 1, and merges width first, left to right:

9 6 3 7 5 1 8 2
9|6|3|7|5|1|8|2           run size = 1
6 9|3 7|1 5|2 8           run size = 2
3 6 7 9|1 2 5 8           run size = 4
1 2 3 5 6 7 8 9           done

Another example of bottom up merge sort algorithm:

http://www.mathcs.emory.edu/~cheung/Courses/171/Syllabus/7-Sort/merge-sort5.html



来源:https://stackoverflow.com/questions/32506758/i-know-how-merge-sort-works-but-how-merge-sort-code-works

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