转自:http://netsmell.com/post/how-sort-10-billion-data.html?ref=myread

海量数据处理/外部归并排序 - 分治.cppp

 

今天要给100亿个数字排序,100亿个 int 型数字放在文件里面大概有 37.2GB,非常大,内存一次装不下了。那么肯定是要拆分成小的文件一个一个来处理,最终在合并成一个排好序的大文件。

实现思路

1.把这个37GB的大文件,用哈希分成1000个小文件,每个小文件平均38MB左右(理想情况),把100亿个数字对1000取模,模出来的结果在0到999之间,每个结果对应一个文件,所以我这里取的哈希函数是 h = x % 1000,哈希函数取得”好”,能使冲突减小,结果分布均匀。

2.拆分完了之后,得到一些几十MB的小文件,那么就可以放进内存里排序了,可以用快速排序,归并排序,堆排序等等。

3.1000个小文件内部排好序之后,就要把这些内部有序的小文件,合并成一个大的文件,可以用二叉堆来做1000路合并的操作,每个小文件是一路,合并后的大文件仍然有序。

首先遍历1000个文件,每个文件里面取第一个数字,组成 (数字, 文件号) 这样的组合加入到堆里(假设是从小到大排序,用小顶堆),遍历完后堆里有1000个 (数字,文件号) 这样的元素
然后不断从堆顶拿元素出来,每拿出一个元素,把它的文件号读取出来,然后去对应的文件里,加一个元素进入堆,直到那个文件被读取完。拿出来的元素当然追加到最终结果的文件里。
按照上面的操作,直到堆被取空了,此时最终结果文件里的全部数字就是有序的了。
最后我用c++写了个实验程序,具体代码在这里可以看到。

如何拆分大文件?

一个32G的大文件,用fopen()打开不会全部加载到内存的,然后for循环遍历啊,把每个数字对1000取模,会得到0到999种结果,然后每种结果在写入到新的文件中,就拆分了


 
 

 

// 对 2 亿个数字进行排序, 约 10 G 的文件, 每个数字 int 能表示
  3 // 算法流程
  4 // 将 10 G 的文件散列到 300 个文件中, 每个文件大约 35 MB
  5 // 对 35 MB 的小文件内部排序, 或者分发到多台计算机中, 并行处理 MapReduce
  6 // 最后使用最小堆, 进行 300 路归并排序, 合成大文件
  7 // 再写一个算法判断 2 亿个数字是否有序
  8  
  9 >
  10 >
  11 >
  12 >
  13 >
  14  
  15 // 哈希文件数
  16 a) (a % FILE_NUM)
  17  
  18 // 2 亿个数字, 手动改
  19 // 待排文件
  20 // 排序后文件
  21 // 临时目录
  22  
  23 // 随机生成 2 亿个数字
  24 void)
  25 {
  26 NULL;
  27   int i;
  28  
  29
  30
  31 0;
  32  
  33 int s, e;
  34 clock();
  35 0; i<num; i++)
  36   {
  37 clock();
  38 // 计算进度
  39     {
  40 100.0) / num);
  41       s = e;
  42     }
  43
  44 31623));
  45   }
  46   fclose(out);
  47 1;
  48 }
  49  
  50 // 对 2 亿个数字进行哈希, 分散到子文件中
  51 // 入口参数: path, tmpdir
  52 void)
  53 {
  54 NULL;
  55 5];
  56 // 哈希文件地址
  57   int data, add;
  58   int i;
  59  
  60
  61
  62 0;
  63 NULL;
  64  
  65   // 开始哈希, 核心代码要尽可能的加速
  66 int s, e;
  67 clock();
  68 0;
  69
  70   {
  71 HASH(data);
  72 NULL)
  73     {
  74
  75
  76     }
  77
  78  
  79     i++;
  80 // 计算进度
  81 1000)
  82     {
  83 100.0) / num);
  84       s = e;
  85     }
  86   }
  87 0; i<FILE_NUM; i++)
  88 fclose(tmp[i]);
  89   fclose(in);
  90  
  91 1;
  92 }
  93  
  94 // 对 300 个文件逐个排序, 采用堆排序 STL 的优先队列
  95 void)
  96 {
  97 // 判断文件存在
  98 // 堆排序
  99 512];
  100 NULL;
  101   int i, data;
  102  
  103   // 逐个处理 300 个文件, 或者将这些文件发送到其它计算机中并行处理
  104 0; i<FILE_NUM; i++)
  105   {
  106
  107 fileexist(hashfile))
  108     {
  109
  110  
  111       // 小文件从磁盘加入内存中
  112
  113
  114       {
  115 push(data);
  116         // 优先队列默认是大顶堆, 即降序排序
  117         // 要升序需要重载 () 运算符
  118       }
  119       fclose(fp);
  120  
  121       // 排序后再从内存写回磁盘
  122 // 覆盖模式写
  123 empty())
  124       {
  125 top());
  126 pop();
  127       }
  128       fclose(fp);
  129     }
  130   }
  131 }
  132  
  133 // 队列结点
  134 {
  135   int data;
  136 // 哈希文件的编号
  137 const
  138 data; }
  139 }node;
  140  
  141 // 将 300 个有序文件合并成一个文件, K 路归并排序
  142 void)
  143 {
  144 char *path);
  145 // 堆排序
  146 5];
  147 NULL;
  148 512];
  149   node tmp, p;
  150 0;
  151  
  152
  153
  154 0;
  155 NULL;
  156 // 打开全部哈希文件
  157   {
  158
  159 fileexist(hashfile))
  160     {
  161
  162 data);
  163 id = i;
  164 // 初始化队列
  165 // 计数器
  166 100.0) / FILE_NUM);
  167     }
  168   }
  169 int s, e;
  170 clock();
  171 // 开始 K 路归并
  172   {
  173 top();
  174 pop();
  175     // 将堆顶的元素写回磁盘, 再从磁盘中拿一个到内存
  176 data);
  177 data) != EOF)
  178     {
  179 id;
  180 push(p);
  181       count++;
  182     }
  183  
  184 // 计算进度
  185 1000)
  186     {
  187 100.0) / num);
  188       s = e;
  189     }
  190   }
  191 0; i<FILE_NUM; i++)
  192 fclose(file[i]);
  193   fclose(out);
  194  
  195 1;
  196 }
  197  
  198 // 检查是否降序排序
  199 {
  200 NULL;
  201   int max = 0x7FFFFFFF;
  202   int data;
  203 0;
  204  
  205
  206
  207 0;
  208  
  209 int s, e;
  210 clock();
  211
  212   {
  213     if (data <= max) max = data;
  214     else
  215     {
  216       fclose(in);
  217 0;
  218     }
  219     count++;
  220 // 计算进度
  221 1000)
  222     {
  223 100.0) / num);
  224       s = e;
  225     }
  226   }
  227   fclose(in);
  228 1;
  229 }
  230  
  231 // 判断文件存在
  232 char *path)
  233 {
  234 NULL;
  235  
  236
  237   if (fp)
  238   {
  239     fclose(fp);
  240 1;
  241   }
  242 0;
  243 }
  244  
  245 void)
  246 {
  247 // 删除目录
  248 // 设置隐藏
  249 // 建立目录
  250  
  251   // 初始化 cmd 命令, 建立工作目录
  252
  253
  254
  255 system(cmd_del);
  256 // 建立工作目录
  257 // 隐藏目录
  258  
  259   // 随机生成 2 亿个数字
  260 0;
  261  
  262 // 对 2 亿个数字进行哈希, 即 Map
  263 // 对 300 个文件逐个排序
  264 // 最后将 300 个有序文件合并成一个文件, 即 reduce
  265
  266
  267  
  268 // 删除哈希文件
  269 // 删除 2 亿数字文件
  270 // 删除排序后的文件
  271  
  272 0;
  273 }

 

 



 

相关文章:

  • 2022-12-23
  • 2021-10-07
  • 2021-05-20
  • 2022-12-23
  • 2021-12-09
  • 2021-11-03
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-12-13
  • 2021-12-07
  • 2022-02-19
  • 2022-12-23
  • 2022-12-23
  • 2021-06-04
相关资源
相似解决方案