合并排序问题 - 在C ++中实现

时间:2015-06-10 19:08:44

标签: c++ mergesort

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

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

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

这是代码,算法的相应步骤在注释中。执行此操作是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]<<" ";
}

2 个答案:

答案 0 :(得分:1)

L[i]=A[p+i];                            //   5.    L[i] = A[p+i-1]

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

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

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

答案 1 :(得分: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