您的位置:首页 > 大数据

外排序(大数据文件排序)

2015-11-23 15:33 295 查看
内排序方法的共同特点是在排序的过程中所有数据都在内存中。但是当待排序的记录数目特别多时,在内存中不能一次处理。必须把他们以文件的形式存放于外存,排序时再把他们一部分一部分地调入内存进行处理。这样,在排序过程中必须不断地在内存与外存之间传送数据。这种基于外部储存设备(或文件)的排序技术就是外排序。

操作系统读写磁盘所需的时间远远超过内存运算时间,基于磁盘(文件)进行的排序多使用归并排序方法。排序分为两个阶段:

第一阶段建立为外排序所用的内存缓冲区。根据他们的大小将输入文件划分为若干段,用某种有效的内排序方法(例如本博客中用快速排序),对各段进行排序。这些排序后的排序段,写到外存中。
利用二路归并思想,把第一阶段生成的初始段加以归并,一趟趟地扩大归并段和减少归并段的个数,直到最后归并成一个大归并段(有序文件)为止。

现在以一个示例加以说明(包含提供完整代码),对2百万个数字进行排序(可以自己编写程序随机生成2百万个数字)。

利用简单的两路归并函数merge对两个归并段进行归并时,仅需把这两个归并段中的记录逐块读入内存,所以这种方法能够对很大的归并段进行排序。

void merge(int numberOfSegments, int segmentSize,char* f1, char* f2, char* f3)
{
if (numberOfSegments > 1)
{
mergeOneStep(numberOfSegments, segmentSize, f1, f2, f3);
merge((numberOfSegments + 1) / 2, segmentSize * 2, f3, f1, f2);
}
else
{ // rename f1 as the final sorted file
copyFile(f1, "sortedlargedata.dat");
cout << "\nSorted into the file sortedlargedata.dat" << endl;
}
}
其中mergeOneStep函数,以及copyFile函数如下:

void mergeOneStep(int numberOfSegments, int segmentSize, char* f1,char* f2, char* f3)
{
fstream f1Input;
f1Input.open(f1, ios::in | ios::binary);

fstream f2Output;
f2Output.open(f2, ios::out | ios::binary);

// Copy half number of segments from f1.dat to f2.dat
copyHalfToF2(numberOfSegments, segmentSize, f1Input, f2Output);
f2Output.close();

// Merge remaining segments in f1 with segments in f2 into f3
fstream f2Input;
f2Input.open(f2, ios::in | ios::binary);
fstream f3Output;
f3Output.open(f3, ios::out | ios::binary);

mergeSegments(numberOfSegments / 2, segmentSize, f1Input, f2Input, f3Output);

f1Input.close();
f2Input.close();
f3Output.close();
}
void copyHalfToF2(int numberOfSegments, int segmentSize, fstream &f1,
fstream &f2)
{
for (int i = 0; i < (numberOfSegments / 2) * segmentSize; i++)
{
int value;
f1.read(reinterpret_cast<char *> (& value), sizeof(value));
f2.write(reinterpret_cast<char *> (& value), sizeof(value));
}
}
void mergeSegments(int numberOfSegments, int segmentSize, fstream &f1,fstream &f2, fstream &f3)
{
for (int i = 0; i < numberOfSegments; i++)
{
mergeTwoSegments(segmentSize, f1, f2, f3);
}

// f1 may have one extra segment, copy it to f3
while (!f1.eof())
{
int value;
f1.read(reinterpret_cast<char *> (& value), sizeof(value));
if (f1.eof()) break;
f3.write(reinterpret_cast<char *> (& value), sizeof(value));
}
}
void mergeTwoSegments(int segmentSize, fstream &f1, fstream &f2,fstream &f3)
{
int intFromF1;
f1.read(reinterpret_cast<char *> (& intFromF1), sizeof(intFromF1));
int intFromF2;
f2.read(reinterpret_cast<char *> (& intFromF2), sizeof(intFromF2));
int f1Count = 1;
int f2Count = 1;

while (true)
{
if (intFromF1 < intFromF2)
{
f3.write(reinterpret_cast<char *>(&intFromF1), sizeof(intFromF1));
if (f1.eof() || f1Count++ >= segmentSize)
{
if (f1.eof()) break;
f3.write(reinterpret_cast<char *>(&intFromF2), sizeof(intFromF2));
break;
}
else
{
f1.read(reinterpret_cast<char *> (& intFromF1), sizeof(intFromF1));
}
}
else
{
f3.write(reinterpret_cast<char *>(&intFromF2), sizeof(intFromF2));
if (f2.eof() || f2Count++ >= segmentSize)
{
if (f2.eof()) break;
f3.write(reinterpret_cast<char *>(&intFromF1), sizeof(intFromF1));
break;
}
else {
f2.read(reinterpret_cast<char *> (& intFromF2), sizeof(intFromF2));
}
}
}

while (!f1.eof() && f1Count++ < segmentSize) {
int value;
f1.read(reinterpret_cast<char *> (& value), sizeof(value));
if (f1.eof()) break;
f3.write(reinterpret_cast<char *> (& value), sizeof(value));
}

while (!f2.eof() && f2Count++ < segmentSize) {
int value;
f2.read(reinterpret_cast<char *> (& value), sizeof(value));
if (f2.eof()) break;
f3.write(reinterpret_cast<char *> (& value), sizeof(value));
}
}


void copyFile(char * f1, char * target)
{
fstream input;
input.open(f1, ios::in | ios::binary);

fstream output;
output.open(target, ios::out | ios::binary);
int i = 0;
while (!input.eof()) // Continue if not end of file
{
int value;
input.read(reinterpret_cast<char *> (& value), sizeof(value));
if (input.eof()) break;
output.write(reinterpret_cast<char *> (& value), sizeof(value));
}

input.close();
output.close();
}
第一阶段代码(其中mergeOneStep函数也属于第一阶段):
int initializeSegments(int segmentSize, char* originalFile, char* f1)
{
int *list = new int[segmentSize];

fstream input;
input.open(originalFile, ios::in | ios::binary);
fstream output;
output.open(f1, ios::out | ios::binary);

int numberOfSegments = 0;
while (!input.eof()) {
int i = 0;
for ( ; !input.eof() && i < segmentSize; i++) {
input.read(reinterpret_cast<char *> (& list[i]), sizeof(list[i]));
}

if (input.eof()) i--;
if (i <= 0)
break;
else
numberOfSegments++;

// Sort an array list[0..i-1]
quickSort(list, i);

// Write the array to f1.dat
for (int j = 0; j < i; j++) {
output.write(reinterpret_cast<char *> (& list[j]), sizeof(list[j]));
}
}

input.close();
output.close();
delete [] list;
return numberOfSegments;
}
主函数:
int main()
{
const int MAX_ARRAY_SIZE = 100;

// Implement Phase 1: Create initial segments
int numberOfSegments =
initializeSegments(MAX_ARRAY_SIZE, "largedata.dat", "f1.dat");

// Implement Phase 2: Merge segments recursively
merge(numberOfSegments, MAX_ARRAY_SIZE, "f1.dat", "f2.dat", "f3.dat");

fstream input;
int value;
input.open("sortedlargedata.dat",ios::in|ios::binary);
for(int i=0;i<100;i++)
{
input.read(reinterpret_cast<char *>(&value),sizeof(value));
cout<<value<<" ";
}

input.close();
return 0;
}
以及快速排序QuickSort.h:

void quickSort(int list[],int arraySize);
void quickSort(int list[],int first,int last);
int partition(int list[],int first,int last);

void quickSort(int list[],int arraySize)
{
quickSort(list,0,arraySize-1);
}

void quickSort(int list[],int first,int last)
{
if(last>first)
{
int pivotIndex=partition(list,first,last);
quickSort(list,first,pivotIndex-1);
quickSort(list,pivotIndex+1,last);
}
}

int partition(int list[],int first,int last)
{
int pivot=list[first];
int low=first+1;
int high=last;

while(high>low)
{
while(low<=high&&list[low]<=pivot)
low++;

while(low<=high&&list[high]>pivot)
high--;

if(high>low)
{
int temp=list[high];
list[high]=list[low];
list[low]=temp;
}
}

while(high>first&&list[high]>=pivot)
high--;

if(pivot>list[high])
{
list[first]=list[high];
list[high]=pivot;
return high;
}
else
{
return first;
}
}


可以在http://wenku.baidu.com/view/a6bfc3859ec3d5bbfd0a74f8下载完整代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: