可以有人编写并解释mergesort的合并部分吗?

huangapple go评论56阅读模式
英文:

Can someone code and explain the merge portion of mergesort?

问题

我一直在尝试理解归并排序中合并部分,已经花了几个小时,看了很多教程和演示。但我不太理解归并排序的合并部分。从理论上来说,我明白。但是尝试通过代码来实现它是我遇到困难的地方。并不是说我不理解它的任何合并部分。我明白为什么需要一些指针来跟踪索引以及while循环中条件语句背后的原因。但在那之后,我卡住了。我在合并方法中写了一条注释,说明我卡在哪里。如果有人能解释一下我需要在Java中编写什么代码以及背后的原因,那就太好了。

编辑:在合并方法中添加了两个新的while循环。我认为我要做的就是如何将排序后的分区复制到input数组中。我想在那之后应该可以正常工作... 希望如此。

编辑2:不要理会上面的,我刚刚看到它没有正确排序。希望有人可以修改我的代码并解释他们的过程。

public static void merge(int[] input, int start, int mid, int end) {
    if (input[mid - 1] <= input[mid]) {
        return;
    }
    int i = start;
    int j = mid;
    int tempIndex = 0;

    int[] temp = new int[end - start];

    // 如果i大于mid或j大于end,这意味着数组的一半已经排序
    while (i < mid && j < end) {
        temp[tempIndex++] = input[i] <= input[j] ? input[i++] : input[j++];
    }
    // 添加了下面两个循环
    while (i < mid) {
        temp[tempIndex++] = input[i++];
    }
    while (j < end) {
        temp[tempIndex++] = input[j++];
    }

    // 现在你需要将排序后的temp数组复制回input数组
    System.arraycopy(temp, 0, input, start, tempIndex);
}
英文:

Ive been trying to understand the merge portion of mergesort for a few hours now, and Ive looked at a bunch of tutorials and walkthroughs. And im not understanding the merge part of mergesort. Theoretically, I understand it. But trying to implement it through code is where Im having a hard time. It's not like I dont understand any of the merge portion of it. I get why you need a couple pointers to keep track of the indices and the reasoning behind the conditional statement in the while loop. But after that I get stuck. I wrote a comment in the merge method on where im stuck. If anyone could just explain to me what I need to code in Java and the reasoning behind it, it'd be great.

EDIT: Added two new while loops the the merge method. All thats left I think for me to do is how to copy the sorted partitions into the input array. I think after that it should be working fine... hopefully.

EDIT2: Nevermind the above, I just saw that its not sorting it correctly. Hopefully someone can just modify my code and explain there process

    public static void merge(int[] input, int start, int mid, int end) {
        if (input[mid - 1] &lt;= input[mid]) {
            return;
        }
        int i = start;
        int j = mid;
        int tempIndex = 0;

        int[] temp = new int[end - start];
        
        //If i is greater than mid or j is greater than end, that means that half of the array is sorted
        while (i &lt; mid &amp;&amp; j &lt; end) {
            temp[tempIndex++] = input[i] &lt;= input[j] ? input[i++] : input[j++];
        }
        //added the two loops below
        while(i &lt; mid){
            temp[tempIndex++] = input[i++];
        }
        while(j &lt; end){
            temp[tempIndex++] = input[j++];
        }
        
    }
    ```

</details>


# 答案1
**得分**: 1

MergeSort是一种分治策略。

假设你有8个元素。
- 这8个元素被分成每个4个元素(左/右),并对每个元素调用mergeSort。现在我们先忽略merge,深入探讨一下。
- 这4个元素进一步分成每个2个元素,并在2个元素数组上调用mergeSort。
- 这2个元素再进一步分成每个1个元素,并在每个元素上调用mergeSort,此时它会立即返回而不执行任何操作。
- 所以最终我们到达了第一次调用merge。那么merge做什么呢?merge将两个已排序的列表合并在一起。当它们每个都只有1个元素时,只需要选择其中一个。所以让我们跳到4个元素并提供下面的示例:

在4个元素子列表调用merge时,它可能具有以下内容:
```plaintext
1 3 2 4

每个子数组(1, 3)和(2, 4)已经由前面的merge排序。所以现在我们需要在合并它们的同时对数组进行排序,像这样(我将使用一个单独的输出数组来演示应该发生的事情,但它也可以原地进行):

for (int i = 0, j = 2, k = 0; k < 4; k++)
{
    int idx;
    if ((j >= 4) || (i < 2 && inputArray[i] < inputArray[j]))
    {
        idx = i++;
    }
    else // j < 4 && (i > 2 || inputArray[j] < inputArray[i])
    {
        idx = j++;
    }
    outputArray[k] = inputArray[idx];
}

正如你所看到的,最初i指向1,j指向2。因为1 < 2,所以选择i,输出1。因为选择了i,所以i被递增。现在,i指向3,j指向2。因为2 < 3,所以选择j...如此循环,直到我们用尽所有元素。

合并后,它将在具有2个4元素侧的较大数组上调用,重复上述过程。

以下是没有硬编码的通用代码:

public void Merge(int[] input, int start, int mid, int end)
{
    if (input[mid - 1] <= input[mid])
    {
    }
    else
    {
        int[] tmp = new int[end - start];
        for (int i = start, j = mid, k = 0; k < tmp.Length; k++)
        {
            int idx;
            if ((j >= end) || (i < mid && input[i] < input[j]))
            {
                idx = i++;
            }
            else // j < end && (i > mid || inputArray[j] < inputArray[i])
            {
                idx = j++;
            }
            tmp[k] = input[idx];
        }

        for (int i = start, j = 0; i < end; i++, j++)
        {
            input[i] = tmp[j];
        }
    }
}
英文:

MergeSort is a divide and conquor strategy.

Let's say you have 8 elements.

  • The 8 elements get split into 4 elements each (left/right) and mergeSort is invoked on each of them. We'll ignore merge for now and delve deeper.
  • The 4 elements are further split into 2 elements each, and mergeSort is invoked on the 2 element array.
  • The 2 elements are further split into 1 elements each, and mergeSort is invoked on each of these at which time, it returns without doing anything.
  • So we are finally at the first invocation of merge. So what does merge do? Merge joins 2 SORTED lists. When they are 1 element each, it's just a matter of picking one over the other. So lets skip forward to the 4 elements and provide an example below:

By the time the 4 element sub-list invokes merge, it may have the following:

1 3 2 4

Each sub-array (1, 3) and (2, 4) are already sorted by the previous merge. So we now need to sort the array while merging them like this (I will use a separate output array to demonstrate what should be happening but it can be done in place):

for (int i = 0, j = 2, k = 0; k &lt; 4; k++)
{
    int idx;
    if ((j &gt;= 4) || (i &lt; 2 &amp;&amp; inputArray[i] &lt; inputArray[j]))
    {
        idx = i++;
    }
    else // j &lt; 4 &amp;&amp; (i &gt; 2 || inputArray[j] &lt; inputArray[i])
    {
        idx = j++;
    }
    outputArray[k] = inputArray[idx];
}

As you can see, initially we have i pointing to 1, j pointing to 2. Because 1 < 2, i is selected, and the 1 is output. Because i was selected, i gets incremented. Now, we have i pointing to 3 and j pointing to 2. Because 2 < 3, j gets selected... and so on until we run out of elements.

And after the merge, it will get called on the larger array with 2 4-element sides, repeating the above.

Below is the generalized code without hard coding

        public void Merge(int[] input, int start, int mid, int end)
        {
            if (input[mid - 1] &lt;= input[mid])
            {
            }
            else
            {
                int[] tmp = new int[end - start];
                for (int i = start, j = mid, k = 0; k &lt; tmp.Length; k++)
                {
                    int idx;
                    if ((j &gt;= end) || (i &lt; mid &amp;&amp; input[i] &lt; input[j]))
                    {
                        idx = i++;
                    }
                    else // j &lt; end &amp;&amp; (i &gt; mid || inputArray[j] &lt; inputArray[i])
                    {
                        idx = j++;
                    }
                    tmp[k] = input[idx];
                }

                for (int i = start, j = 0; i &lt; end; i++, j++)
                {
                    input[i] = tmp[j];
                }
            }
        }

huangapple
  • 本文由 发表于 2020年8月12日 05:45:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/63366801.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定