【问题标题】:What is wrong with my C++ merge sort program?我的 C++ 合并排序程序有什么问题?
【发布时间】:2012-03-21 00:33:19
【问题描述】:

我在这个实现上陷入了僵局。我的 n2 变量在子数组的合并过程中被覆盖,这可能是什么原因造成的?我尝试过硬编码值,但它似乎不起作用。

#include <iostream>
#include <cstdlib>
#include <ctime> // For time(), time(0) returns the integer number of seconds from the     system clock
#include <iomanip>
#include <algorithm> 
#include <cmath>//added last nite 3/18/12 1:14am

using namespace std;

int size = 0;

void Merge(int A[], int p, int q, int r)
{
    int i,
        j,
        k,
        n1 = q - p + 1,
        n2 = r - q;

    int L[5], R[5];

    for(i = 0; i < n1; i++)
        L[i] = A[i];

    for(j = 0; j < n2; j++)
        R[j] = A[q + j + 1];

    for(k = 0, i = 0, j = 0; i < n1  && j < n2; k++)//for(k = p,i = j = 1; k <= r; k++)
    {
        if(L[i] <= R[j])//if(L[i] <= R[j])
        {
            A[k] = L[i++];
        } else {
            A[k] = R[j++];
        }
    }
}

void Merge_Sort(int A[], int p, int r)
{
    if(p < r)
    {
        int q = 0;
        q = (p + r) / 2;
        Merge_Sort(A, p, q);
        Merge_Sort(A, q+1, r);
        Merge(A, p, q, r);
    }
}

void main()
{
    int p = 1,
        A[8];

    for (int i = 0;i < 8;i++) {
        A[i] = rand();
    }
    for(int l = 0;l < 8;l++)
    {
        cout<<A[l]<<"  \n";
    }
    cout<<"Enter the amount you wish to absorb from host array\n\n";
    cin>>size;
    cout<<"\n";
    int r = size; //new addition
    Merge_Sort(A, p, size - 1);

    for(int kl = 0;kl < size;kl++)
    {
        cout<<A[kl]<<"  \n";
    }

}

【问题讨论】:

  • 欢迎来到Stack Overflow。请注意,如果您提供少量输入、他们的输出以及您期望的输出,其他人向您提供反馈要容易得多。

标签: c++ arrays algorithm sorting mergesort


【解决方案1】:

您使用什么工具来编译程序?有一些标志可以打开检查这类事情,例如gcc(例如 -fmudflap,我没用过,但它看起来很有用)。

如果您可以使用调试器(例如 gdb),您应该能够为变量 n2 添加“数据监视”,并且调试器将在检测到任何写入 n2 的内容时停止程序。这应该可以帮助您追踪错误。或者试试valgrind

暂时停止此类错误的一种简单技术是在被丢弃的错误周围放置一些虚拟变量,因此:

int dummy1[100];
int n2 = r - q;
int dummy2[100];

int L[5], R[5];

变量被丢弃通常是由超出数组范围的代码编写引起的。 罪魁祸首可能是R[5],因为这可能是最接近的。您可以查看假人以查看正在编写的内容,并且可以从中推断出正在发生的事情。

另一种选择是让所有数组都变大,同时跟踪问题。再次将超出正确范围的值设置为已知值,并检查那些应该不变的值。

你可以做一个小宏来做这些检查,然后把它放在任何方便的地方。

【讨论】:

  • @Thomas - 我认为这是一个真正的、重要的补充:-) 我在 80 年代初学习了 C,并教它。我们在 DOS PC 上没有调试器,甚至没有操作系统:-) 所以我们有点“贫民窟”,因为我们别无选择。我仍然坚信 C 是一门出色的学习语言,因为您无需学习汇编程序即可获得机器上正在发生的事情的非常具体的模型 :-) 并且这种理解在其他上下文中很有用,并且相对可移植。跨度>
  • @gbulmer,非常正确,当然不是贬义的,这种方法在很多情况下都可以证明自己非常有用。它本身也有点神秘——并不是每个人都会想到超越自己的变量,尤其是在这个时代。
  • @Thomas - 虽然我强烈支持教授现代类型安全、垃圾收集的语言,但它并没有为人们准备足够的计算模型。我现在在微控制器(我们世界的实际计算结构)上做了很多工作,我们又回到了 C 或 C++ 的一个子集(没有动态内存分配:-),也没有受保护的操作系统,所以这一切都很重要.
【解决方案2】:

我之前使用过类似的 Merge 功能,但它似乎无法正常工作。然后我重新设计,现在它工作得很好。下面是重新设计的 C++ 中合并函数的函数定义。

void merge(int a[], int p, int q, int r){
    int n1 = q-p+1;             //no of elements in first half
    int n2 = r-q;               //no of elements in second half
    int i, j, k;

    int * b = new int[n1+n2];   //temporary array to store merged elements

    i = p;
    j = q+1;
    k = 0;
    while(i<(p+n1) && j < (q+1+n2)){     //merging the two sorted arrays into one
        if( a[i] <= a[j]){
            b[k++] = a[i++];
        }
        else 
            b[k++] = a[j++];
    }

    if(i >= (p+n1))         //checking first which sorted array is finished
        while(k < (n1+n2))      //and then store the remaining element of other 
            b[k++] = a[j++];    //array at the end of merged array.
    else
        while(k < (n1+n2))
            b[k++] = a[i++];

    for(i = p,j=0;i<= r;){      //store the temporary merged array at appropriate  
        a[i++] = b[j++];        //location in main array.
    }

    delete [] b;
}

希望对你有帮助。

【讨论】:

    【解决方案3】:
    void Merge(int A[], int p, int q, int r)
    {
        int i,
            j,
            k,
            n1 = q - p + 1,
            n2 = r - q;
    
        int L[5], R[5];
    
        for(i = 0; i < n1; i++)
            L[i] = A[i];
    

    您只分配L[5],但您使用的n1 绑定是基于输入qp——并且允许调用者调用具有q 和@ 值的函数987654328@ 允许在L[] 的范围之外写入。这可以表现为覆盖任何其他自动变量,但由于它是未定义的行为,几乎任何事情都可能发生。 (包括security vulnerabilities。)

    我不知道解决这个问题的最佳方法是什么——我不明白为什么你在Merge() 中有固定长度的缓冲区,我没有仔细阅读以发现原因——但是你当i 大于或等于5 时,不应访问L[i]

    整个对话也适用于R[]。而且,由于*A 被传递给Merge(),因此确保对它的数组访问也始终处于绑定状态是有意义的。 (我没有发现它们越界,但由于这段代码无论如何都需要重新编写,我不确定是否值得我仔细寻找它们。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      相关资源
      最近更新 更多