运行Merge Sort实现时的结果

时间:2015-10-14 02:09:46

标签: c++ arrays sorting mergesort

我正在尝试实现时间分析的Merge排序,当测试用于实现此功能的函数时,我得到了一些时髦的结果,并且无法弄清楚原因。我生成一个包含20个随机值的数组,然后调用mergeSort然后打印“已排序”数组的结果。

没有错误消息,但结果不符合预期。输出将显示为前几个值排序,然后在它们之间的一些0,并最终以非常大的值结束,即使生成的数字应该在1和100之间。输出如下:

>sort-timings
1 3 8 11 0 14 17 24 0 0 29 96 20 2293400 3 2293400 2293400 26085452 1971496002 1971496002 >Exit code: 0    Time: 0.4162

我实施的代码是:

void merge(int A[], int leftStart, int leftEnd, int rightStart, int rightEnd, int W[]) {
   //Merge A[leftStart]....[leftEnd] with A[rightStart]...[rightEnd]
   //Into W, indexed by k, copy resulting W into A
   int i = leftStart;
   int j = rightStart;
   int k = leftStart;
   while( i <= leftEnd && j <= rightEnd) {
      if(A[i] < A[j]) {
         W[k++] = A[i++];
      }
      else if(A[i] > A[j]) {
         W[k++] = A[j++];
      }
      else {
         W[k++] = A[i++];
         W[k++] = A[j++];
      }
   }
   for(i = leftStart; i <= rightEnd; i++) {
      A[i] = W[i];
   }
}

void mergeSort(int A[], int low, int high, int W[]) {
   //mergeSort Helper Function
   if(low == high) {
      return; //1 element is sorted
   }
   int mid = (low + high) / 2;
   mergeSort(A, low, mid, W); //Sort first half
   mergeSort(A, mid + 1, high, W); //Sort second half
   merge(A, low, mid, mid + 1, high, W);
   return;
}

void mergeSort(int A[], int W[], int n) {
   mergeSort(A, 0, n - 1, W);
}

void generateRandomArray(int A[], int n) {
   unsigned int seed = time(0);
   srand(seed);
   for(int i = 0; i < n; i++) {
      A[i] = (rand() % 100) + 1; // 1 <= A[i] <=10000
   }
}

int main() {
   const int ARRAY_SIZE = 20;
   int array[ARRAY_SIZE];
   int tempArray[ARRAY_SIZE];
   generateRandomArray(array, ARRAY_SIZE);
   mergeSort(array, tempArray, ARRAY_SIZE);   
   for(int i = 0; i < ARRAY_SIZE; i++) {
      cout << array[i] << " ";
   }
}

2 个答案:

答案 0 :(得分:1)

您要提前停止merge循环。当i超出范围 j超出范围时,它会暂停,这会使一些值未复制到W,从而导致您的未初始化值输出

解决此问题的一种简单方法是在主循环完成后复制其余值。如果循环因i超出范围而结束,则要复制j的其余部分,类似地,如果循环结束,因为j超出范围,则要复制其余部分i

您可以通过在主循环后添加循环来实现此目的,以确保ij到达其范围的末尾:

while (i <= leftEnd) {
    W[k++] = A[i++];
}
while (j <= rightEnd) {
    W[k++] = A[j++];
}

在将for复制到W的最终A循环之前放置。

另一个替代方法是更改​​循环,使条件为||,这意味着它将继续,而任何一个数字都在范围内。然后,在使用之前,必须测试一个数字是否在范围内。有很多方法可以做到这一点,一种简单的方法是先测试它:

while (i <= leftEnd || j <= rightEnd) {
    if (j > rightEnd) {
        W[k++] = A[i++];
    }
    else if (i > leftEnd) {
        W[k++] = A[j++];
    }
    else if (A[i] < A[j]) {
    ...

答案 1 :(得分:1)

使用标志(mtoa)根据递归级别跟踪合并方向的备用版本,以避免复制数据。它还只在TopDownMerge()中递增索引后检查索引超出范围;我不确定这是否会产生显着的性能差异。

void TopDownMergeSort(int a[], int b[], size_t n)
{
    if(n < 2)
        return;
    TopDownSplitMerge(a, b, 0, n, true);
}

void TopDownSplitMerge(int a[], int b[], size_t ll, size_t ee, bool mtoa)
{
size_t rr;
    if ((ee - ll) == 1){                    // if size == 1
        if(!mtoa)                           //  copy to b if merging a to b
            b[ll] = a[ll];
        return;
    }
    rr = (ll + ee)>>1;                      // midpoint, start of right half
    TopDownSplitMerge(a, b, ll, rr, !mtoa);
    TopDownSplitMerge(a, b, rr, ee, !mtoa);
    if(mtoa)                                // if merging to a, merge b to a
        TopDownMerge(b, a, ll, rr, ee);
    else                                    // else merge a to b
        TopDownMerge(a, b, ll, rr, ee);
}

void TopDownMerge(int a[], int b[], size_t ll, size_t rr, size_t ee)
{
    size_t o = ll;                          // b[]       index
    size_t l = ll;                          // a[] left  index
    size_t r = rr;                          // a[] right index
    while(1){                               // merge data
        if(a[l] <= a[r]){                   // if a[l] <= a[r]
            b[o++] = a[l++];                //   copy a[l]
            if(l < rr)                      //   if not end of left run
                continue;                   //     continue (back to while)
            while(r < ee){                  //   else copy rest of right run
                b[o++] = a[r++];
            }
            break;                          //     and return
        } else {                            // else a[l] > a[r]
            b[o++] = a[r++];                //   copy a[r]
            if(r < ee)                      //   if not end of right run
                continue;                   //     continue (back to while)
            while(l < rr){                  //   else copy rest of left run
                b[o++] = a[l++];
            }
            break;                          //     and return
        }
    }
}