合并排序,I/O使用文件显示分割故障
Merge Sort, I/O using files shows Segmentation Fault
当通过控制台给出输入时,用C 编写的以下Mergesort程序在没有任何错误中工作。但是,当我使用文本文件提供输入时,它会给我一个细分错误。我尝试在代码的各个部分打印消息以检查错误的位置,但是除了D SEG失控消息外,它没有打印任何东西。这是代码。当我不使用文件给输入/显示输出时,它可以正常工作。
我在VirtualBox 4.0.8(Ubuntu OS)中的GCC编译器上运行了此PROG,其基本内存为1 GB。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;
}
输入文件8362891410
您的索引还有很多不足之处。我不会害羞地告诉您,也不只是说我不会以这种方式合并。但这就是它的本质,所以我将介绍它。
重要的是要了解,使用划分和征服算法进行序列排序都是关于在序列中传递某些基本参考,以及该参考文献中的一些偏移。该算法应独立于外部变量(例如array[]
和barray[]
),并将其作为参数。此外,请记住您在C (或C)中编程。两种语言的美的一部分是他们的本地指针 - 算术能力。它可以很好地用于Merge-Sort等算法。在我演示您的合并和Mergesort函数应该如何工作之后,我将演示我在说什么,然后我会在C 中提供最琐碎的合并排序标准库功能。
您的代码首先
首先使用参数重新滚动您的函数。我将参数重命名为它们实际上对审稿人有意义的自由。该算法应该是不言自明的,我敦促您将其并排比较。
// 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);
}
此算法的注释是传递的初始参数必须是序列中的有效索引。换句话说,如果您阅读了8个元素的数组,则有效索引为 0..7
,因此您将其调用为mergesort(0,7)
。
另一种方法
C/C 中的传统合并使用数组基数和长度作为其唯一参数。中点由排序算法计算。尽管合并算法并非严格需要(它也可以使用长度/2),但它使您需要从现在不在中间不拆分的细分市场中合并的算法上更强大的算法。
不要挂在下面的std :: vector,std :: randy_device等的用法上。它们仅在main()
函数中用于填充一个随机数的数组,然后在排序操作之前和之后进行排序,显示,显示。我希望您摆脱的是实际算法本身。
#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;
}
输出(变化)
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
您会讨厌的部分
经历了所有这些工作后,您会很高兴知道,标准库中已经存在两个为您合并的算法,即std::merge
和std::inplace_merge
。使用其中之一使实施mergesort
Trivial ,如下所示:
#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);
}
请记住,如果您除了std::sort
以外还需要使用某些东西,那么,除了实现学术目的外,它诚实地将所有这些都陷入了几乎无用的地步。
因此,鉴于您的输入,当p = 1和r = 1时,您在随后呼叫的Mergesort中使用Q的非初始化值。
您收到的错误是由于Mergesort函数中无界的递归。
- 如何使 windows 命令提示符在C++可执行文件上显示返回值?
- gtkmm 显示文件内容
- 如何从QFile阅读?它显示该文件不可访问
- 在QTreeView中仅显示共享驱动器和文件夹
- 如何在 MFC 中显示文件的所有行
- 禁止显示有关包含文件中 #pragma 包的警告
- Visual Studio C++ 它只构建选项卡中显示的文件吗?
- 在 txt 文件中显示前两个数字的程序
- 使用 Cmake 在 Qt Creator 中显示头文件
- 如何从文件中显示蛋糕名称?
- 与clang++一起使用的VS代码在构建良好的C++文件中显示错误
- 如何从文件显示布尔值表
- 合并排序,I/O使用文件显示分割故障
- 文件I/O-显示文件的内容
- 一般生成文件显示没有规则来生成目标错误
- 使用 C++ 和 Qt 如何将 16 位原始文件显示为图像
- eclipse(stm32)Why中的项目资源管理器中,一些stderivi文件显示为灰色
- 将大 CSV 文件显示为表格
- Visual studio .cu文件显示语法错误,但编译成功
- 列表未从 TXT 文件显示