外排序(大数据文件排序)
2015-11-23 15:33
295 查看
内排序方法的共同特点是在排序的过程中所有数据都在内存中。但是当待排序的记录数目特别多时,在内存中不能一次处理。必须把他们以文件的形式存放于外存,排序时再把他们一部分一部分地调入内存进行处理。这样,在排序过程中必须不断地在内存与外存之间传送数据。这种基于外部储存设备(或文件)的排序技术就是外排序。
操作系统读写磁盘所需的时间远远超过内存运算时间,基于磁盘(文件)进行的排序多使用归并排序方法。排序分为两个阶段:
第一阶段建立为外排序所用的内存缓冲区。根据他们的大小将输入文件划分为若干段,用某种有效的内排序方法(例如本博客中用快速排序),对各段进行排序。这些排序后的排序段,写到外存中。
利用二路归并思想,把第一阶段生成的初始段加以归并,一趟趟地扩大归并段和减少归并段的个数,直到最后归并成一个大归并段(有序文件)为止。
现在以一个示例加以说明(包含提供完整代码),对2百万个数字进行排序(可以自己编写程序随机生成2百万个数字)。
利用简单的两路归并函数merge对两个归并段进行归并时,仅需把这两个归并段中的记录逐块读入内存,所以这种方法能够对很大的归并段进行排序。
可以在http://wenku.baidu.com/view/a6bfc3859ec3d5bbfd0a74f8下载完整代码
操作系统读写磁盘所需的时间远远超过内存运算时间,基于磁盘(文件)进行的排序多使用归并排序方法。排序分为两个阶段:
第一阶段建立为外排序所用的内存缓冲区。根据他们的大小将输入文件划分为若干段,用某种有效的内排序方法(例如本博客中用快速排序),对各段进行排序。这些排序后的排序段,写到外存中。
利用二路归并思想,把第一阶段生成的初始段加以归并,一趟趟地扩大归并段和减少归并段的个数,直到最后归并成一个大归并段(有序文件)为止。
现在以一个示例加以说明(包含提供完整代码),对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下载完整代码
相关文章推荐
- select count(*) as total from(select count(*) from tab_cb_casim group by `card_no`) as cai;
- 053-15 Which tasks are run automatically as part of the Automated Maintenance Task by default? (Choo
- RAID配置与管理详解
- 1090. Highest Price in Supply Chain (25)
- 1090. Highest Price in Supply Chain (25)
- apk反编译出错:Exception in thread "main" brut.androlib.AndrolibException: Could not decode ars c file
- codeforces 579A Raising Bacteria
- Could not reliably determine the server's fully qualified domain name
- type_traits.h
- stl_pair.h
- MyBatis批量操作报错:Parameter 'xxxList' not found. Available parameters are [list]
- Codeforces Round #185 (Div. 2) C. The Closest Pair 构造
- 多线程(银行存款)使用notify()和wait()线程通信实现交替存款
- 217. Contains Duplicate
- 从大数据菜鸟走上大师的历程 第三讲:Tuple Array Map
- hadoop特性讲解
- 什么是领域驱动设计(Domain Driven Design)?
- LeetCode OJ——Submission Details
- LinkedIn高级分析师王益:大数据时代的理想主义和现实主义(图灵访谈)
- 数据库 大数据