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

Issue with Merge Sort - Implementation in C++

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

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

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

这是代码,算法的相应步骤在注释中。其执行是 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]<<" ";
}
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 开始,但在这里您没有。

您对 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 answer to Sorting of an array using merge sort