我正在遵循 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]<<" ";
}
答案 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
的递归调用表明p
和r
是要排序的子数组的第一项和最后一项的索引:
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]
位置。