简体   繁体   English

合并排序,使用文件的I / O显示分段错误

[英]Merge Sort, I/O using files shows Segmentation Fault

The following mergesort program written in C++ works without any error when the inputs are given through the console. 当通过控制台提供输入时,以C ++编写的以下mergesort程序可以正常工作。 But when I use text files to give the inputs, it gives me a segmentation error. 但是当我使用文本文件来提供输入时,它会给我一个分段错误。 I have tried printing messages at various parts of the code to check where is the mistake, but it isn't printing anything except d seg-fault message. 我已经尝试在代码的各个部分打印消息以检查错误在哪里,但除了d seg-fault消息之外它不会打印任何内容。 Here is the code. 这是代码。 It works fine when I do not use files for giving the inputs/ displaying the output. 当我不使用文件来提供输入/显示输出时,它工作正常。

I ran this prog on a gcc compiler in a virtualbox 4.0.8(ubuntu OS) with a base memory of 1 GB. 我在一个基本内存为1 GB的virtualbox 4.0.8(ubuntu OS)中的gcc编译器上运行此prog。 Cud the error be due to insufficient memory? Cud错误是由于内存不足?

#include<iostream>
#include<fstream>
#include<sys/time.h>
using namespace std;

int array[50];
int barray[50];

void merge(int p,int q, int r)
 {
    int i,j,k,l;
    l=p;
    i=p;
    j=q+1;

    while((i<=q)&&(j<=r))
    {

     if(array[i]<=array[j])
        barray[++k]=array[i++];

     else
        barray[k++]=array[j++];

    }

    if(i>q)
    {  
       for(l=j;l<=r;l++)
       { 
         barray[k]=array[l];
         k++;
       }
    }

   else
   {
      for(l=i;l<=q;l++)
      {
        barray[k]=array[l];
        k++;
      }

   }

   for(i=p;i<=r;i++)
        array[i]=barray[i];
}

void mergesort(int p, int r)
{
   int q;

   if(p<r)
      q=(p+r)/2;

   mergesort(p,q);
   mergesort(q+1,r);
   merge(p,q,r);

}


int main()
{
  int r, p, i;

  struct timeval tv1, tv2;/* For finding the running time */
  gettimeofday(&tv1, NULL);

  ifstream fin;
  ofstream fout;

  fin.open("abc5.txt");
  fout.open("new5.txt");

  fin>>r;
  while(fin)
  {

    for(i=1;i<=r;++i)
    {
       fin>>array[i];
    }

  }

  mergesort(1,r);

  for(i=1;i<=r;++i)
  {
    fout<<array[i]<<"\n";
  }

  gettimeofday(&tv2, NULL);
  fout<<"Running Time: "<<(double) (tv2.tv_usec - tv1.tv_usec) / 1000000 + (double)    (tv2.tv_sec - tv1.tv_sec)<<" sec";


 fin.close();
 fout.close();

 return 0;

}

THE INPUT FILE 8 3 6 2 8 9 1 4 10 输入文件 8 3 6 2 8 9 1 4 10

Your indexing leaves much to be desired. 你的索引还有很多不足之处。 I will not be shy about telling you that, nor about saying simply that I would not do merge-sort this way. 我不会羞于告诉你,也不会简单地说我不会这样合并排序。 But it is what it is, so I'll cover it. 但事实就是这样,所以我会介绍它。

It is important to understand that sequence sorting using divide and conquer algorithms are all about passing some base reference within the sequence and some offsets from that reference. 重要的是要理解使用分而治之算法的序列排序都是关于在序列中传递一些基本参考以及从该参考传递一些偏移。 The algorithm should be independent of external variables (like array[] and barray[] ) and take them as parameters instead. 该算法应独立于外部变量(如array[]barray[] ),并将它们作为参数。 Further, remember you're programming in C++ (or C). 此外,请记住您使用C ++(或C)进行编程。 Part of the beauty of both languages is their native pointer-arithmetic ability. 两种语言的部分优点是它们的原生指针算术能力。 It can be wonderfully used for algorithms like merge-sort. 它可以奇妙地用于像merge-sort这样的算法。 After I demonstrate how your merge and mergesort functions should work, I'll demonstrate what I'm talking about, then I'll proffer up the most-trivial merge sort you can do in C++ if you utilize the standard libraries functionality. 之后我展示你的合并和归并职能应该如何工作的,我将演示一下我说的,那我就毫无顾忌了最平凡的合并排序,你可以用C ++做的,如果你使用标准库的功能。


Your Code First 你的代码优先

First a re-roll of your function using your parameters. 首先使用参数重新编写函数。 I've taken the liberty of renaming the parameters to they're actually meaningful to the reviewer. 我冒昧地将参数重命名为对评论者来说实际上有意义。 The algorithm should be self-explanatory and I urge you to compare it side-by-side with what you were doing. 该算法应该是不言自明的,我敦促你将它与你正在做的事情并排比较。

//  low  = starting index
//  mid  = middle index
//  high = last index
void merge(int low, int mid, int high)
{
    int i=low, j=mid, k=0;

    while (i < mid && j <=high)
    {
        if (array[i] < array[j])
            barray[k++] = array[i++];
        else
            barray[k++] = array[j++];
    }

    // finish whichever segment isn't done
    while (i < mid)
        barray[k++] = array[i++];
    while (j <= high)
        barray[k++] = array[j++];

    // copy back
    for (i=0;i<k;++i)
        array[low+i] = barray[i];
}

void mergesort(int low, int high)
{
    int len = high - low;
    if (len < 2)
        return;

    int mid = low + len/2;
    mergesort(low, mid);
    mergesort(mid, high);
    merge(low, mid, high);
}

Of note to this algorithm is the initial parameters passed must be valid indexes in the sequence. 值得注意的是,该算法的初始参数必须是序列中的有效索引。 In other words, if you read an array of 8-elements, the valid indexes are 0..7 and therefore you would invoke it as mergesort(0,7) . 换言之,如果读8-元件的阵列,该有效索引0..7 ,因此,你将调用它作为mergesort(0,7)


A Different Approach 一种不同的方法

The traditional merge sort in C/C++ uses an array base-index and length as its only parameters. C / C ++中的传统合并排序使用数组基索引和长度作为唯一参数。 The midpoint is calculated by the sort-algorithm. 中点由排序算法计算。 Though it is not strictly needed for the merge algorithm, (it too can just use length/2), it makes for a more robust algorithm on the off-chance you ever need merging from a segment that is not split right now the middle. 虽然并非严格需要合并算法,(它也可以只使用长度/ 2),但它可以为您提供一个更加强大的算法,您需要从现在中间未分割的段合并。

Don't get hung up on the usage of std::vector, std::random_device, etc below. 不要挂在下面使用std :: vector,std :: random_device等。 They're used in the main() function solely to populate an array of random numbers that is then sorted, displayed both before and after the sort operation. 它们在main()函数中仅用于填充随机数组,然后在排序操作之前和之后对其进行排序。 What I want you to get out of this is the actual algorithm itself. 我想让你摆脱这个是实际的算法本身。

#include <iostream>
#include <vector>
#include <random>

void merge(int ar[], std::size_t mid, std::size_t len)
{
    if (len < 2)
        return;

    // temporary storage. normally I use a RAII container
    //  such as std::vector<>, but I wanted to demonstrate
    //  the algorithm and indexing, not the memory management.
    //  none the less it is worth noting.
    int *tmp = new int[len];
    std::size_t i=0, j=mid, k=0;

    while (i < mid && j < len)
    {
        if (ar[i] < ar[j])
            tmp[k++] = ar[i++];
        else
            tmp[k++] = ar[j++];
    }

    // complete the unfinished segment
    while (i < mid)
        tmp[k++] = ar[i++];
    while (j < len)
        tmp[k++] = ar[j++];

    // and move back to the original array
    for (i=0; i<len; ++i)
        ar[i] = tmp[i];

    delete [] tmp;
}

void mergesort(int ar[], std::size_t len)
{
    if (len < 2)
        return;

    // note pointer arithemtic in second call.
    mergesort(ar, len/2);
    mergesort(ar+len/2, len - len/2);
    merge(ar, len/2, len);
}

int main()
{
    std::vector<int> data;
    data.reserve(20);

    std::random_device rd;
    std::default_random_engine rng(rd());
    std::uniform_int_distribution<> dist(1,50);

    // populate array
    std::generate_n(std::back_inserter(data),
                data.capacity(),
                [&](){ return dist(rng);});

    // show on-screen
    for (auto n : data)
        std::cout << n << ' ';
    std::cout << '\n';

    // mergesort
    mergesort(data.data(), data.size());

    // show on-screen
    for (auto n : data)
        std::cout << n << ' ';
    std::cout << '\n';

    return 0;
}

Output (varies) 输出 (变化)

15 10 8 38 20 21 9 43 8 22 19 45 12 16 17 36 2 32 6 37 
2 6 8 8 9 10 12 15 16 17 19 20 21 22 32 36 37 38 43 45 

The Part You'll Hate 你讨厌的部分

After going through all this work you'll be not-so-happy to know that two algorithms that do segment merging for you are already present in the standard library, namely std::merge and std::inplace_merge . 完成所有这些工作之后,您将不会很高兴地知道为您进行分段合并的两个算法已经存在于标准库中,即std::mergestd::inplace_merge Using one of those makes implementing mergesort trivial , as you'll see below: 使用其中一个使得实现mergesort 微不足道 ,如下所示:

#include <algorithm>

void mergesort(int ar[], std::size_t len)
{
    if (len < 2)
        return;

    mergesort(ar, len/2);
    mergesort(ar+len/2, len-len/2);
    std::inplace_merge(ar, ar+len/2, ar+len);
}

Remember that if you ever need to use something besides std::sort , which honestly puts all of this to a point of near-uselessness besides fulfilling academic purpose. 请记住,如果你需要使用除了std::sort之外的其他东西,除了实现学术目的之外,诚实地将所有这些都放在几乎无用的地方。

So given your input, it looks like when p=1 and r=1 that you use an uninitialized value for q in subsequent calls to mergesort. 因此,根据您的输入,当p = 1且r = 1时,您在后续调用mergesort时使用未初始化的q值。

The error you're receiving is because of unbounded recursion in the mergesort function. 您收到的错误是由于mergesort函数中的无限递归。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM