合并排序不正确的输出 c++

Mergesort incorrect output c++

本文关键字:输出 c++ 不正确 排序 合并      更新时间:2023-10-16

输入:{10,9,8,7,6,5,4,3,2,1}输出 :{8,7,6,9,10,5,4,3,2,1}

我不确定问题是什么。我认为这与合并排序中的递归有关。我是递归的新手,所以我的理解不是很好。有什么提示吗?

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

一般问题是指针混淆。C 语言的一个怪癖并不明显,那就是在

void mergeSort(int a[], int t[], int n);

at都不是数组,而是指针。在语言标准中对此有一条特殊规则。这意味着在调用堆栈上mergeSort的所有实例化中,ta引用相同的内存区域,这意味着每次您执行类似

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++];
}
}

在解释错误之前,让我首先强调一下,像int a[]这样的函数参数只不过是传递给函数的指针。它指向内存区域。

现在,mergesort需要一些临时内存,并且通过以下方式工作

  1. 将数据复制到临时存储器;
  2. 对临时内存中的每一半数据进行排序;
  3. 合并两半,从而写入原始数组。

在步骤 2 中,不需要原始数组,可以用作递归的临时内存。

鉴于这些事实,您的代码包含两个错误:

  1. 您没有正确使用数组t[]a[]。这个想法是a[]既是输入又是输出,t[]临时数组。在内部,数据首先被复制到临时数组中,其中的每一部分都经过排序,然后合并它们填充原始数组a[]

  2. 您不会对临时数组的后半部分进行排序,而是对前半部分进行两次排序。

例如,正确的实现是:

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