合并排序问题 - 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
的递归调用表明 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]
位置。
编辑
参见 my answer to Sorting of an array using merge sort。
我遵循合并排序 算法 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
的递归调用表明 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]
位置。
编辑
参见 my answer to Sorting of an array using merge sort。