【问题标题】:Issue with Merge Sort - Implementation in C++合并排序的问题 - C++ 中的实现
【发布时间】:2015-06-10 19:08:44
【问题描述】:

我正在遵循 Cormen 的算法简介2.3.1中建议的合并排序算法。但是,我没有得到正确的输出。我确信这里有一些愚蠢的错误,但我已经有一段时间无法弄清楚了。任何帮助将不胜感激。

例如:对于输入:5,4,3,2,1,我的输出是 3 1 2 4 5 而不是 1 2 3 4 5

假设代码将针对非常小的数字进行测试,并且用999 替换标记值∞(在算法中)不会影响程序。

这里是代码,算法的相应步骤在cmets中。执行此操作是here

#include <iostream>
using namespace std;

void merge(int* A, int p, int q, int r) {       // MERGE(A,p,q,r)
    int n1 = q-p+1;                             //   1. n1 = q-p+1
    int n2 = r-q;                               //   2. n2 = r-q 

    int i,j,k;
    int *L=new int[n1+1], *R = new int[n2+1];   //   3. let L[1...n1+1] and R[1..n2+1] be new arrays

    for(i=0; i<n1; i++)                         //   4. for i = 1 to n1
        L[i]=A[p+i];                            //   5.    L[i] = A[p+i-1]
       //the modification in above line is deliberately done to avoid IndexOutOfBounds when p=i=0 and is not because I forgot to subtract 1               
    for(j=0; j<n2;j++)                          //   6. for j = 1 to n2
        R[j]=A[q+j];                            //   7.    R[j] = A[q+j]

    L[n1]=999; //sentinel                       //   8. L[n1+1]= ∞
    R[n2]=999; //sentinel                       //   9. R[n2+1]= ∞
    i=0;                                        //  10. i = 1
    j=0;                                        //  11. j = 1
    for(k=p; k<r; k++) {                        //  12. for k = p to r 
        if(L[i]<=R[j])                          //  13.    if(L[i]<=R[j])
            A[k]=L[i++];                        //  14.         A[k] = L[i]
                                                //  15.         i = i+1
        else                                    //  16.    else A[k] = R[j]
            A[k]=R[j++];                        //  17.         j = j+1                 
    }

    delete(L);
    delete(R);
}

void mergeSort(int* a, int p, int r) {        // MERGE-SORT (A,p,r)
    if(p<r) {                                 //  1. if p<r 
        int q=(p+r)/2;                        //  2.   q = (p+r)/2 
        mergeSort(a,p,q);                     //  3.   MERGE-SORT(A,p,q)
        mergeSort(a,q+1,r);                   //  4.   MERGE-SORT(A,q+1,r)
        merge(a,p,q,r);                       //  5.   MERGE(A,p,q,r)
    }
}

int main() {
    int arr[]={5,4,3,2,1};
    mergeSort(arr,0,5);

    for(int i=0; i<5; i++)
        cout << arr[i]<<" ";
}

【问题讨论】:

  • “但是,我没有得到正确的输出。”你得到什么输出?预期的输出是多少?请提供Minimal, Complete, Verifiable Example
  • 我添加了ideone链接供大家查看。但为了完整起见,我仍然会对其进行编辑。 :)
  • 另外...您不想对大于 999 的数字进行排序?
  • 没有。仅适用于小数字。如果需要,我总是可以通过调用库函数将标记更改为可能的最大整数。但现在,我只想对小数字进行排序。
  • @Cheersandhth.-Alf,我只是想理解算法,所以使用了一个整数数组。我现在并没有真正实施任何大的东西。否则,与此相比,库调用非常有效。

标签: c++ mergesort


【解决方案1】:

您对mergeSort 的递归调用表明pr 是要排序的子数组的第一项和最后一项的索引:

void mergeSort(int* a, int p, int r) {
    if(p<r) {
        int q=(p+r)/2;
        mergeSort(a,p,q);
        mergeSort(a,q+1,r);
        merge(a,p,q,r);
    }
}

如果是这样,您在main 中的调用不正确:

int arr[]={5,4,3,2,1};
mergeSort(arr,0,5);

应该是

int arr[]={5,4,3,2,1};
mergeSort(arr,0,4);

接下来,复制后半部分是错误的:

R[j]=A[q+j];

应该是:

R[j]=A[q+1+j];

注意p是左半部分第一项的索引,而q是左半部分最后一项的索引——所以右半部分的第一项有索引q+1,这应该作为+j的基础。

最后,

for(k=p; k<r; k++) 

应该阅读

for(k=p; k<=r; k++) 

r是右边部分最后一项的索引,所以需要填充合并子数组的[r]位置。

编辑
请参阅my answerSorting of an array using merge sort

【讨论】:

    【解决方案2】:
    L[i]=A[p+i];                            //   5.    L[i] = A[p+i-1]
    

    我认为这是你的问题,你没有遵循这里的算法,通过稍微修复它(不使用 -1,因为你从 0 开始)但是在下一个循环中,当你算法中也不是从相同的数字开始?

    R[j]=A[q+j];                            //   7.    R[j] = A[q+j]
    

    在上一个循环中,您手动更正从 0 开始,而不是 1,但在这里您不需要。

    【讨论】:

    • 更改R[j] = A[q+j+1]。当j=n2-1 表示A[q+n2] = A[q+r-q] = A[r]。对于r=5(我的初次通话),这意味着OutOfBounds
    • @Anindya Dutta 似乎纠正一个循环而不是另一个循环使得代码与源算法不一致,不是吗?为什么不将初始值保持为 1,并将条件从 '
    • 是的,我会尝试考虑索引[1...n] 中的所有数组。不过似乎浪费了0th 索引。 :\
    • 哈哈,是的。但是对一个循环进行硬编码,同时保持另一个循环不变(这使您的算法与原始算法不同)可能会导致逻辑问题。
    • 确实,更改 R[j]=A[q+j+1] 确实有效。谢谢你。对于我提到它的部分,我很抱歉outOfBounds
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多