Mergesort输出错误c ++

时间:2018-02-12 11:04:15

标签: 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;
}

2 个答案:

答案 0 :(得分:0)

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

现在,mergesort需要一些临时内存并按

工作
  1. 将数据复制到临时存储器;
  2. 对临时存储器中的每一半数据进行排序;
  3. 合并两半,从而写入原始数组。
  4. 在第2步中,不需要原始数组,它可以作为递归的临时内存。

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

    1. 您没有恰当地使用数组t[]a[]。我们的想法是a[]既是输入又是输出,t[]是临时数组。在内部,数据首先被复制到临时数组,每个数据都被排序,然后合并它们填充原始数组a[]

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

    3. 正确的实现是,例如,

      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);

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