输入:{10,9,8,7,6,5,4,3,2,1}
输出:{8,7,6,9,10,5,4,3,2,1}
我不确定问题是什么。我认为它与mergesort中的递归有关。我是递归的新手,所以我的理解不太好。任何提示?
#include <iostream>
void mergeSort(int a[], int w[], int n);
void merge(int a[], int w[], int n);
using namespace std;
void mergeSort(int a[], int t[], int n) {
if (n > 1) {
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
for (int i = n/2; i < n; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
merge(a, t, n/2);
}
}
void merge(int a[], int t[], int n) {
int leftIndex = 0, leftEnd = n/2;
int rightIndex = n/2, rightEnd = n;
int targetIndex = 0;
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < t[rightIndex])
a[targetIndex++] = t[leftIndex++];
else
a[targetIndex++] = t[rightIndex++];
}
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
while (rightIndex < rightEnd) {
a[targetIndex++] = t[rightIndex++];
}
}
int main() {
const int SIZE = 10;
int a[] = {10,9,8,7,6,5,4,3,2,1};
int w[SIZE];
mergeSort(a,w,SIZE);
for (int i = 0; i < SIZE; i++) {
cout << a[i] << " ";
}
cout << endl;
}
答案 0 :(得分:0)
在解释错误之前,让我首先强调像int a[]
这样的函数参数只不过是传递给函数的指针。它指向一个记忆区域。
现在,mergesort
需要一些临时内存并按
在第2步中,不需要原始数组,它可以作为递归的临时内存。
鉴于这些事实,您的代码包含两个错误:
您没有恰当地使用数组t[]
和a[]
。我们的想法是a[]
既是输入又是输出,t[]
是临时数组。在内部,数据首先被复制到临时数组,每个数据都被排序,然后合并它们填充原始数组a[]
。
您不对临时数组的后半部分进行排序,而是对上半部分进行两次排序。
正确的实现是,例如,
void mergeSort(int*a, int*t, int n) {
if (n > 1) {
for (int i = 0; i < n; i++)
t[i] = a[i]; // copy to temporary
mergeSort(t , a , n/2); // sort 1st half of temporary
mergeSort(t+n/2, a+n/2, n-n/2); // sort 2nd half of temporary
merge(a, t, n);
}
}
请注意,由于t[]
和a[]
是指针,因此操作t+n/2
只是获取指向数组后半部分的指针。具有此更改的代码的结果是1 2 3 4 5 6 7 8 9 10
。
答案 1 :(得分:0)
一般问题是指针混乱。其中一个不明显的C语言怪癖是
void mergeSort(int a[], int t[], int n);
a
和t
都不是数组,而是指针。在语言标准中有一个特殊的规则。这意味着在调用堆栈中mergeSort
的所有实例化中,t
和a
指的是相同的内存区域,这意味着每次执行类似1}的操作时p>
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
您正在更改相同的内存区域。完成此操作并返回上一个调用框后,此区域不再包含您希望其包含的数据。
解决此问题的方法是在merge
中定义您需要的临时本地缓冲区。例如:
const int SIZE = 10;
// mergeSort is much simpler now:
void mergeSort(int a[], int n) {
if (n > 1) {
// sort the left side, then the right side
mergeSort(a , n / 2);
mergeSort(a + n / 2, n - n / 2);
// then merge them.
merge(a, n);
}
}
// Buffer work done in merge:
void merge(int a[], int n) {
// temporary buffer t, big enough to hold the left side
int t[SIZE];
int leftIndex = 0 , leftEnd = n / 2;
int rightIndex = n / 2, rightEnd = n ;
int targetIndex = 0;
// copy the left side of the target array into the temporary
// buffer so we can overwrite that left side without worrying
// about overwriting data we haven't yet merged
for(int i = leftIndex; i < leftEnd; ++i) {
t[i] = a[i];
}
// then merge the right side and the temporary buffer to
// the left side. By the time we start overwriting stuff on
// the right side, the values we're overwriting will have been
// merged somewhere into the left side, so this is okay.
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < a[rightIndex]) {
a[targetIndex++] = t[leftIndex++];
} else {
a[targetIndex++] = a[rightIndex++];
}
}
// If there's stuff in the temporary buffer left over,
// copy it to the end of the target array. If stuff on the
// right is left over, it's already in the right place.
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
}