1、1亿个整数排序。
主要有两种方法,一种是利用归并进行外部排序,思想如下:
(1)将文件中的数据按固定长度读入内存数组中,快排后,存入不同的文件中。
(2)同时打开这些文件,读入第一个到临时数组中,找最小的数,若找到,则对应的文件读下一个。
(3)若当前文件读完,在标志数组位置置为false.
(4)直到所有标志都为false循环结束。
代码如下:
#include <iostream>
#include<fstream>
using namespace std;
const int dataSize=5;
int compare(const void *num1,const void *num2)
{
return *(int*)num1-*(int*)num2;
}
int main()
{
ifstream in("data.txt");
int a[dataSize];
int count=0;
int fileNum=0;
char fileName[20];
ofstream out;
while(in>>a[count]) //读完之后自动移到下一个位置
{
count++;
if(count==dataSize || in.cur==in.eof())//表示数组已满//或者是最后一个数了
{
fileNum++;
qsort(a,count,sizeof(int),compare);
sprintf(fileName,"%d.txt",fileNum);//显得更加简洁
out.open(fileName);
for(int i=0;i<count;i++)
out<<a[i]<<" ";
out<<endl;
out.close();
count=0;
}
}
in.close();
//k路合并
ifstream *inFile=new ifstream[fileNum];
out.open("result.txt");
int *tempDataArray=new int[fileNum];//存储数字
bool *hasNextFlag=new bool[fileNum];//存储是否有下一个的标志
for(int i=0;i<fileNum;i++)
{
sprintf(fileName,"%d.txt",i+1);
inFile[i].open(fileName);
inFile[i]>>tempDataArray[i];
hasNextFlag[i]=true;
}
bool hasDataFlag=true;
while(hasDataFlag)
{
int minData=0x7FFFFFFF,minSn;
hasDataFlag=false;
for(int i=0;i<fileNum;i++)
{
if(hasNextFlag[i]&&tempDataArray[i]<minData)
{
minData=tempDataArray[i];
minSn=i;
hasDataFlag=true;
}
}
if(hasDataFlag)
{
out<<minData<<" ";
if(!(inFile[minSn]>>tempDataArray[minSn]))
hasNextFlag[minSn]=false;
}
}
out<<endl;
out.close();
for(int i=0;i<fileNum;i++)
{
inFile[i].close();
delete []inFile[i];
}
delete []inFile;
delete []tempDataArray;
system("pause");
return 0;
}
测试文件data.txt数据为:
12 32 5 4
5 8
9 45 44444 6 8 45 78 9 23 12 45 78 5 2 6 65 68 69 67 62 63 51 52 57 58 59
分批读入后,不同文件数据为:
1.txt 4 5 5 12 32
2.txt 6 8 9 45 44444
3.txt 8 9 23 45 78
4.txt 2 5 12 45 78
5.txt 6 65 67 68 69
6.txt 51 52 57 62 63
7.txt 58 59
归并后数据为:
2 4 5 5 5 6 6 8 8 9 9 12 12 23 32 45 45 45 51 52 57 58 59 62 63 65 67 68 69 78 78 44444
方法2:
利用位图进行排序,但是有要求,数据不能重复,总体数据量比较小。因为有多少个数据,就必须定义多少位。一个字节有8位,那么一亿个数据的话接近100M的内存。
这里只对100以内的数进行排序,然后只能用内存中的5位,那么需要20趟才能搞定。也就是说对于6到10的,将踏减去5之后就能用1到5位了,返回的时候加上5输出即可。
代码如下:
#include <iostream>
#include<fstream>
#include<bitset>
using namespace std;
const int MaxScanSize=5;
const int ScanTimes=20;
int main()
{
ifstream in("data.txt");
ofstream out("result.txt");
bitset<MaxScanSize> BitMap; //下标从0开始
for(int i=0;i<ScanTimes;i++)
{
BitMap.reset();
int inData;
while(!in.eof())
{
in>>inData;
if(inData>(i*MaxScanSize)&&inData<=(i+1)*MaxScanSize)
BitMap.set(inData-(i*MaxScanSize)-1,1);
}
for(int j=0;j<MaxScanSize;j++)
{
if(BitMap[j]==1)
out<<(i*MaxScanSize)+j+1<<" ";
}
in.clear();//必须要清除之后才能重新指向,这是个重大的问题
in.seekg(0);//指向文件的开头,这里是绝对位置,要想使相对位置可以用seekg(0,ios::beg)
in>>inData;
}
in.close();
out.close();
system("pause");
return 0;
}
需要注意的几点:
(1)bitset下标是从0开始。
(2)ifstream读数的时候最好用while(!in.eof())
(3)若需要改变流指针的指向,需要先clear,再指向,用seekg这里有绝对和相对指向,同样有seekp为输出流的指向。
(4)适当的用const代替程序中的数字是一个好的习惯,便于维护。
结果如下:
data.txt:
65 68 69 67 62 63 51 52 57 58 59 2 3 8 9 7
result.txt:
2 3 7 8 9 51 52 57 58 59 62 63 67 68 69
相关的题