[英]Mergesort incorrect output c++
輸入: {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;
}
在解釋錯誤之前,讓我首先強調一下,像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
。
通常的問題是指針混亂。 並非立即顯而易見的C語言怪癖之一是
void mergeSort(int a[], int t[], int n);
a
和t
都不是數組,而是指針。 語言標准中對此有一個特殊的規定。 這意味着在調用堆棧上的mergeSort
所有實例中, t
和a
引用相同的內存區域,這意味着每次您執行類似的操作時,
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++];
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.