【问题标题】:Recursion misbehaving in merge sort合并排序中的递归行为异常
【发布时间】:2019-07-10 18:28:46
【问题描述】:

我的程序中的第二次递归传递了一个奇怪的数组,然后整个过程被破坏了。 我传递了一个数组及其大小,然后将其分为两个数组 left_arrright_arr。我们对左数组继续上述过程,直到它达到基本条件。有一个类似的问题,程序传递高、低值并在同一个数组上进行更改。 我想知道为什么我的代码会突然输出。忽略征服功能,因为在接近它之前发生错误,我无法检查。

我尝试通过打印原始数组、左右数组来调试我的代码,但找不到错误。
好的,我的第一个疑问是程序每次都创建一个新数组,即按值传递? 以及,如何调试此类问题?

#include<bits/stdc++.h>

using namespace std;


 int conquer(int left_arr[],int right_arr[], int arr[]){
    int i=0,j=0,k=0;
    int length_left = sizeof(left_arr)/sizeof(left_arr[0]);
    int length_right = sizeof(right_arr)/sizeof(right_arr[0]);

                                               //int l = length_left + 
 length_right;

  while(i<length_left && j<length_right)
  {
      if(left_arr[i]<=right_arr[j])
      {
          arr[k++] = left_arr[i++];
      }
      else
      {
          arr[k++] = right_arr[j++];
      }
  }
  while(i<length_left)
  {
      arr[k++] = left_arr[i++];
  }

  while(j<length_right)
  {
      arr[k++] = right_arr[j++];
  }


                                                  for(int i=0; i<l;i++)
                                                  cout<<arr[i]<<" ";
                                                    cout<<endl;
return 0;
}

int divide(int *arr,int n)
{

 if(n<2)
  return 0;




  int mid=n/2;
  int x = n-mid;

  cout<<"  n ="<<n<<"  mid ="<<mid<<endl;

  int left_arr[mid];
  int right_arr[n-mid];             //for debug
                                    cout<<"arr:";
                                    for(int m=0;m<n;m++)
                                        cout<<arr[m]<<"  ";
                                    cout<<endl;


  for(int i=0;i<mid;i++)
      left_arr[i]=arr[i];          //for debug
                                   cout<<"Larr:";
                                   for(int k=0;k<mid;k++)
                                    cout<<left_arr[k]<<" ";

                                    cout<<endl;



  for(int j=mid;j<n;j++)
      right_arr[j] = arr[j];
                                cout<<"Rarr:";      //for debug
                                for(int j=mid;j<n;j++)
                                    cout<<right_arr[j]<<" ";

                                    cout<<endl<<endl;


   divide(left_arr,mid);
   divide(right_arr,x);

   //conquer(left_arr,right_arr,arr);


  return 0;
}


int main()
{
  int n,arr[]={2,5,4,6,1,8,3};


  divide(arr,7);

  for(int i=0;i<7;i++)
  {
      cout<<arr[i]<<" ";
  }
    return 0;
}

n =7 中 =3 错误:2 5 4 6 1 8 3 拉尔:2 5 4 拉尔:6 1 8 3

n =3 中 =1 错误:2 5 4 拉尔:2 拉尔:5 4

n =2 中 =1 arr:7536080 5 拉尔:7536080 Rarr:5 //来自这里的错误

n =4 中 =2 arr:-1 0 4200483 6 拉尔:-1 0 Rarr:4200483 6

n =2 中间 =1 错误:-1 0 拉尔:-1 拉尔:0

n =2 中间 =1 arr:7536080 5 拉尔:7536080 拉尔:5

【问题讨论】:

  • int left_arr[mid]; 不是标准 C++,除非 mid 是一个常量表达式。这可能是也可能不是问题的一部分,但您不应该使用非标准语言扩展。
  • int length_left = sizeof(left_arr)/sizeof(left_arr[0]) 是一个错误。至少是标准的c++sizeof(left_arr) 是指针的大小而不是数组的大小。
  • @OP 您知道,如果您使用std::vector 及其工具(例如at() 调用来确定边界访问问题。即使是提到的sizeof 错误也可以通过使用size() 来防止。这就是 VLA 语法对您的健康有害的原因。它隐藏了错误,如果条目数量非常多(堆栈溢出),它会导致错误。
  • #include&lt;bits/stdc++.h&gt;loads the gunusing namespace std;takes the safety off。真的要小心。

标签: c++ recursion mergesort


【解决方案1】:

做,

    for(int j=mid;j<n;j++)
    right_arr[j-mid] = arr[j];

并传递整个数组的大小

   conquer(left_arr,right_arr,arr,n);

在征服功能中,

    int length_left = n/2;
    int length_right = n-length_left;

因为您无法从其指针中找到数组的长度。

【讨论】:

    【解决方案2】:

    这是一个简单的数组访问越界错误(因此是未定义的行为)。

    for(int j=mid;j<n;j++)
        right_arr[j] = arr[j];
    

    应该是

    for(int j=mid;j<n;j++)
        right_arr[j-mid] = arr[j];
    

    此外,正如 cmets 中已经指出的,您使用的可变长度数组 (VLA) 不是合法的 C++。

    【讨论】:

    • 请看一下conquer函数。我得到 1 0 2 0 1 8 3 作为排序后的最终输出。
    • @HarshalSharma 此代码不正确int length_left = sizeof(left_arr)/sizeof(left_arr[0]); 因为left_arr 是指针而不是数组。所以sizeof(left_arr) 是 4(或 8 在 64 位系统上)。它不是原始数组的大小。数组在 C++ 中是垃圾,你真的应该使用向量,但是如果你必须使用数组,那么你应该正确地了解它们能做什么和不能做什么。
    猜你喜欢
    • 2014-12-14
    • 1970-01-01
    • 2021-11-06
    • 2019-01-22
    • 2018-07-26
    • 2014-01-21
    相关资源
    最近更新 更多