簡體   English   中英

Mergesort錯誤輸出C ++

[英]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需要一些臨時內存,並且可以通過

  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

通常的問題是指針混亂。 並非立即顯而易見的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++];
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM