排序算法(七)海量数据的排序问题

     前边几篇文章,整理过各种各样的排序,但是那些排序都是只能在内存中进行排序,而如果给大量的数据(内存中无法容纳),要给这些数据进行排序,我们就需要借助于一种外排序----归并排序(之后的文章详细介绍)。
     对于大数据的排序,我们只能讲数据存储在磁盘上,然后将存储数据的文件进行分割,将小文件中的数据拿到内存中去借助快排进行排序,最后将小文件合并为一个大文件。在这中间,小文件比较多,我将小文件名存储在一个队列中,当队列的大小为1时,合并完毕。
代码中遇到的问题:1.文件名称一样,导致文件的覆盖,程序死循环。 2.在文件合并时,每次从两个文件中分别读到一个数据,只将小的写进 合并文件,当有一个文件已经读取完,另一个文件还没有读完时,我们就应该 将上次读到的数据(还没有写进合并文件)写到文件,再进行读取。
代码缺陷:文件名很糟糕。
下边给出实现代码【代码中我测试1000个数的排序,也测试过10万个数的排序,都是可以的】:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
using namespace std;
#include<string>
#include<assert.h>
#include<vector>
#include<time.h>
#include<algorithm>
#include<queue>

class BigDataSort
{
public:
	BigDataSort(string fileName,size_t size)
		:_fileName(fileName)
		,_size(size)
	{
		//写fileName文件
		FILE* pWrite = fopen(fileName.c_str(),"w");
		assert(pWrite);
		srand( (unsigned)time( NULL )); 
		//随机值函数生成数据写入文件
		for(int i = 0; i < _size; ++i)
		{
			int tmp = rand();
			fprintf(pWrite,"%d",tmp);
			fprintf(pWrite,"%c",'\n');
		}
		fclose(pWrite);
	}
	void Sort()
	{
		_Divide();
		_Merge();
	}
protected:
	
	void _Divide()//读取要排序的文件,分成10个小文件
	{
		vector<int> v;//存放每个小文件的数据
		FILE* pRead = fopen(_fileName.c_str(),"r");
		assert(pRead);
		int count = 1;
		char fileName[] = "0.txt";
		while(count <= 10)
		{
			v.clear();
			//从要排序的文件中读取10分之一的数据,写到v中,在内存中进行排序
			for(int i = 0; i < _size/10 && !feof(pRead); ++i)
			{
				int tmp;
				fscanf(pRead,"%d",&tmp);
				if(tmp == '\n')
					fscanf(pRead,"%d",&tmp);
				v.push_back(tmp);
			}
			sort(v.begin(),v.end());
			//将排序好的整数写进一个小的文件中
			
			FILE* pWrite = fopen(fileName,"w");
			assert(pWrite);
			//将文件名写进文件名的容器
			_smallFileName.push(fileName);
			fileName[0]++;


			for(int i = 0; i < v.size(); ++i)
			{
				fprintf(pWrite,"%d",v[i]);
				fprintf(pWrite,"%c",'\n');
			}
			fclose(pWrite);
			++count;
		}
		fclose(pRead);
	}


	void _Merge()
	{
		char filename[] = "a.txt";
		while(_smallFileName.size() > 1)
		{
			//从文件名的容器中读取两个文件进行合并
			string file1 = _smallFileName.front();
			_smallFileName.pop();
			string file2 = _smallFileName.front();
			_smallFileName.pop();
			
			//将合并的文件名写进文件名容器
			
			FILE* pMergeFile = fopen(filename,"w");
			assert(pMergeFile);
			_smallFileName.push(filename);

			filename[0]++;

			//打开两个文件,并进行读操作
			FILE* pRead1 = fopen(file1.c_str(),"r");
			assert(pRead1);
			FILE* pRead2 = fopen(file2.c_str(),"r");
			assert(pRead2);

			//进行合并
			int tmp1 = 0;
			int tmp2 = 0;
			fscanf(pRead1,"%d",&tmp1);
			fscanf(pRead2,"%d",&tmp2);

			while(!feof(pRead1) && !feof(pRead2))
			{
				while(!feof(pRead1) && !feof(pRead2) && tmp1 <= tmp2)//将tmp1写进合并文件,并继续读取文件1
				{
					fprintf(pMergeFile,"%d",tmp1);
					fprintf(pMergeFile,"%c",'\n');
					fscanf(pRead1,"%d",&tmp1);
				}

				while(!feof(pRead1) && !feof(pRead2) && tmp2 <= tmp1)//将tmp2写进合并文件,并继续读取文件2
				{
					fprintf(pMergeFile,"%d",tmp2);
					fprintf(pMergeFile,"%c",'\n');
					fscanf(pRead2,"%d",&tmp2);
				}
			}
			//有一个文件已经读取完毕
			while(!feof(pRead1))
			{
				fprintf(pMergeFile,"%d",tmp1);
				fprintf(pMergeFile,"%c",'\n');
				fscanf(pRead1,"%d",&tmp1);
			}

			while(!feof(pRead2))
			{
				//将上次读到的数据写进文件
				fprintf(pMergeFile,"%d",tmp2);
				fprintf(pMergeFile,"%c",'\n');
				fscanf(pRead2,"%d",&tmp2);
			}
			//关闭文件
			fclose(pRead1);
			fclose(pRead2);
			fclose(pMergeFile);
			//删除文件
			remove(file1.c_str());
			remove(file2.c_str());
		}
	}
private:
	string _fileName;
	size_t _size;//要排序的数据总数
	queue<string> _smallFileName;
};

void Test()
{
	BigDataSort s("sort.txt",1000);
	s.Sort();
}

如果程序中有不合理的地方,欢迎指出~~~

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值