给海量数据进行排序

本文参照:作者:July,yansha,5,编程艺术室。
                   出处:http://blog.csdn.net/v_JULY_v 

如何给10^7个不重复的数据量的磁盘文件排序?

2种解决方案。

 

    1、归并排序。你可能会想到把磁盘文件进行归并排序,但题目要求你只有1MB的内存空间可用,所以,归并排序这个方法不行。
    2、位图方案。熟悉位图的朋友可能会想到用位图来表示这个文件集合。例如正如编程珠玑一书上所述,用一个20位长的字符串来表示一个所有元素都小于20的简单的非负整数集合,边框用如下字符串来表示集合{1,2,3,5,8,13}:

 

0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0

 

上述集合中各数对应的位置则置1,没有对应的数的位置则置0。

首先尝试用位图方案:

但是经过分析发现如果只用一次那么需要的内存大于1M,但是如果分两次那么每次只需0.65M。

对文件进行第一次扫描,如果小于5000000则进行位图表示,写入文件。

对文件进行第二次扫描,如果大于5000000则进行位图表示,写入文件。

耗时6s。

//copyright@ yansha  
//July、2010.05.30。  
//位图方案解决10^7个数据量的文件的排序问题  
//如果有重复的数据,那么只能显示其中一个 其他的将被忽略  
#include <iostream>  
#include <bitset>  
#include <assert.h>  
#include <time.h>  
using namespace std;  
  
const int max_each_scan = 5000000;  
  
int main()  
{  
    clock_t begin = clock();  
    bitset<max_each_scan> bit_map;  
    bit_map.reset();  
      
    // open the file with the unsorted data  
    FILE *fp_unsort_file = fopen("data.txt", "r");  
    assert(fp_unsort_file);  
    int num;  
  
    // the first time scan to sort the data between 0 - 4999999  
    while (fscanf(fp_unsort_file, "%d ", &num) != EOF)  
    {  
        if (num < max_each_scan)  
            bit_map.set(num, 1);  
    }  
      
    FILE *fp_sort_file = fopen("sort.txt", "w");  
    assert(fp_sort_file);  
    int i;  
      
    // write the sorted data into file  
    for (i = 0; i < max_each_scan; i++)  
    {  
        if (bit_map[i] == 1)  
            fprintf(fp_sort_file, "%d ", i);  
    }  
      
    // the second time scan to sort the data between 5000000 - 9999999  
    int result = fseek(fp_unsort_file, 0, SEEK_SET);  
    if (result)  
        cout << "fseek failed!" << endl;  
    else  
    {  
        bit_map.reset();  
        while (fscanf(fp_unsort_file, "%d ", &num) != EOF)  
        {  
            if (num >= max_each_scan && num < 10000000)  
            {  
                num -= max_each_scan;  
                bit_map.set(num, 1);  
            }  
        }  
        for (i = 0; i < max_each_scan; i++)  
        {  
            if (bit_map[i] == 1)  
                fprintf(fp_sort_file, "%d ", i + max_each_scan);  
        }  
    }  
      
    clock_t end = clock();  
    cout<<"用位图的方法,耗时:"<<endl;  
    cout << (end - begin) / CLK_TCK << "s" << endl;  
    fclose(fp_sort_file);  
    fclose(fp_unsort_file);  
    return 0;  
}  

接下来采用多路归并来解决。

源文件大约是40M,所以把源文件分成40分,每份通过快排得到有序,之后对40份有序文件进行归并排序。

声明一个40个大小的临时数据,一次存入每个文件的头一个数字,然后通过最小堆,把第一个堆里的数字存入文件,然后从那个数字所处的文件中读入下一个数字,直到文件都读完。

大约耗时20s,主要是磁盘的读写很耗时。

 

 

 

 

posted on 2012-06-08 19:35  蓝色守望  阅读(1157)  评论(0)    收藏  举报

导航