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

Issue with Merge Sort - Implementation in C++

本文关键字:C++ 实现 排序 问题 合并      更新时间:2023-10-16

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

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

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

以下是代码和算法的相应步骤,请参阅注释。这是一个执行。

#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]<<" ";
}

您对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]位置。

编辑
请参阅我对使用合并排序对数组进行排序的回答。

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

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

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

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