在这个归并排序的实现中有什么问题?

What is wrong in this implementation of merge sort?

本文关键字:什么 问题 实现 归并排序      更新时间:2023-10-16

我知道有很多合并排序的实现,但这是我在《算法导论》一书中读到的一个。下面的代码是一个不能正常工作的合并排序的实现:

#include <iostream>
using namespace std;
void merge(int*a, int p, int q, int r) {  //function to merge two arrays
  int n1 = (q - p);  // size of first sub array
  int n2 = (r - q);  // size of second subarray
  int c[n1], d[n2];
  for (int i = 0; i <= n1; i++) {
    c[i] = a[p + i];
  }
  for (int j = 0; j <= n2; j++) {
    d[j] = a[q + j];
  }
  int i = 0, j = 0;
  for (int k = p; k < r; k++) {  // merging two arrays in ascending order
    if (c[i] <= d[j]) {
      a[k++] = c[i++];
    } else {
      a[k++] = d[j++];
    }
  }
}
void merge_sort(int*a, int s, int e) {
  if (s < e) {
    int mid = (s + e) / 2;
    merge_sort(a, s, mid);
    merge_sort(a, mid + 1, e);
    merge(a, s, mid, e);
  }
}
int main() {
  int a[7] { 10, 2, 6, 8, 9, 10, 15 };
  merge_sort(a, 0, 6);
  for (auto i : a)
    cout << i << endl;
}

此代码不能正常工作。这段代码有什么问题?怎样才能解决这个问题?

首先你应该正确设置数组的大小。

void merge(int*a, int p, int q, int r) {  //function to merge two arrays
/* If i am not wrong , p is the starting index of the first sub array
   q is the ending index of it also q+1 is the starting index of second  
   sub array and r is the end of it */
/* size of the sub array would be (q-p+1) think about it*/
int n1 = (q - p);  // size of first sub array
/* This is right n2 = (r-(q+1)+1)*/
int n2 = (r - q);  // size of second subarray
int c[n1], d[n2];
for (int i = 0; i < n1; i++) {
c[i] = a[p + i];
}
for (int j = 0; j < n2; j++) {
d[j] = a[q + 1 + j];
}
.
.
.
}

现在,在此之后,您已经将两个数组复制到本地定义的数组中。在此之前,它是正确的。

现在主要的部分是合并两个数组,这是你在for循环中所做的。你只是比较第一个子数组的第i个元素和第二个子数组的第j个元素,但是你在这里错过的是,可能有一段时间你已经更新了主数组中第一个(或第二个)子数组的所有值,但仍然有一些元素保留在第二个(第一个)子数组中。

例如,取以下两个子数组
sub1={2,3,4,5};
sub2={7,8,9,10};

在这种情况下,您应该在完全遍历数组中的任何一个后立即中断循环,并以相同的顺序复制另一个数组的其余元素。同样在for循环中,你在循环中增加k两次,一次是在for语句中,另一次是在更新值的时候,检查一下。

在您的逻辑实现中出现了一些问题。我已在下面清楚地指出:

void merge(int*a,int p,int q,int r){  //function to merge two arrays
int n1= (q-p); // size of first sub array
int n2= (r-q); // size of second subarray
int c[n1+1],d[n2]; //you need to add 1 otherwise you will lose out elements
for(int i=0;i<=n1;i++){
    c[i]=a[p+i];
    }
for(int j=0;j<n2;j++){
    d[j]=a[q+j+1];//This is to ensure that the second array starts after the mid element
    }
    int i=0,j=0;
int k;
for( k=p;k<=r;k++){ // merging two arrays in ascending order
    if( i<=n1 && j<n2 ){//you need to check the bounds else may get unexpected results
        if( c[i] <= d[j] )
            a[k] = c[i++];
        else
            a[k] = d[j++];
    }else if( i<=n1 ){
        a[k] = c[i++];
    }else{
        a[k] = d[j++];
    }
}
}