含有5亿个整数的大文件,如果排序?

给你1个文件bigdata,大小4663M,5亿个数,文件中的数据随机,如下一行一个整数:

61963023557681612158020393452095006174677379343122016371712330287901712966901...7005375

现在要对这个文件进行排序,怎么搞?

内部排序

先尝试内排,选2种排序方式:

 
  1. privatefinalint cutoff = 8;

  2.  

  3. public void perform(Comparable[] a) {

  4. perform(a,0,a.length - 1);

  5. }

  6.  

  7. private int median3(Comparable[] a,int x,int y,int z) {

  8. if(lessThan(a[x],a[y])) {

  9. if(lessThan(a[y],a[z])) {

  10. return y;

  11. }

  12. elseif(lessThan(a[x],a[z])) {

  13. return z;

  14. }else {

  15. return x;

  16. }

  17. }else {

  18. if(lessThan(a[z],a[y])){

  19. return y;

  20. }elseif(lessThan(a[z],a[x])) {

  21. return z;

  22. }else {

  23. return x;

  24. }

  25. }

  26. }

  27.  

  28. private void perform(Comparable[] a,int low,int high) {

  29. int n = high - low + 1;

  30. //当序列非常小,用插入排序

  31. if(n <= cutoff) {

  32. InsertionSort insertionSort = SortFactory.createInsertionSort();

  33. insertionSort.perform(a,low,high);

  34. //当序列中小时,使用median3

  35. }elseif(n <= 100) {

  36. int m = median3(a,low,low + (n >>> 1),high);

  37. exchange(a,m,low);

  38. //当序列比较大时,使用ninther

  39. }else {

  40. int gap = n >>> 3;

  41. int m = low + (n >>> 1);

  42. int m1 = median3(a,low,low + gap,low + (gap << 1));

  43. int m2 = median3(a,m - gap,m,m + gap);

  44. int m3 = median3(a,high - (gap << 1),high - gap,high);

  45. int ninther = median3(a,m1,m2,m3);

  46. exchange(a,ninther,low);

  47. }

  48.  

  49. if(high <= low)

  50. return;

  51. //lessThan

  52. int lt = low;

  53. //greaterThan

  54. int gt = high;

  55. //中心点

  56. Comparablepivot = a[low];

  57. int i = low + 1;

  58.  

  59. /*

  60. * 不变式:

  61. * a[low..lt-1] 小于pivot -> 前部(first)

  62. * a[lt..i-1] 等于 pivot -> 中部(middle)

  63. * a[gt+1..n-1] 大于 pivot -> 后部(final)

  64. *

  65. * a[i..gt] 待考察区域

  66. */

  67.  

  68. while (i <= gt) {

  69. if(lessThan(a[i],pivot)) {

  70. //i-> ,lt ->

  71. exchange(a,lt++,i++);

  72. }elseif(lessThan(pivot,a[i])) {

  73. exchange(a,i,gt--);

  74. }else{

  75. i++;

  76. }

  77. }

  78.  

  79. // a[low..lt-1] < v = a[lt..gt] < a[gt+1..high].

  80. perform(a,low,lt - 1);

  81. perform(a,gt + 1,high);

  82. }

归并排序:

 
  1. /**

  2. * 小于等于这个值的时候,交给插入排序

  3. */

  4. privatefinalint cutoff = 8;

  5.  

  6. /**

  7. * 对给定的元素序列进行排序

  8. *

  9. * @param a 给定元素序列

  10. */

  11. @Override

  12. public void perform(Comparable[] a) {

  13. Comparable[] b = a.clone();

  14. perform(b, a, 0, a.length - 1);

  15. }

  16.  

  17. private void perform(Comparable[] src,Comparable[] dest,int low,int high) {

  18. if(low >= high)

  19. return;

  20.  

  21. //小于等于cutoff的时候,交给插入排序

  22. if(high - low <= cutoff) {

  23. SortFactory.createInsertionSort().perform(dest,low,high);

  24. return;

  25. }

  26.  

  27. int mid = low + ((high - low) >>> 1);

  28. perform(dest,src,low,mid);

  29. perform(dest,src,mid + 1,high);

  30.  

  31. //考虑局部有序 src[mid] <= src[mid+1]

  32. if(lessThanOrEqual(src[mid],src[mid+1])) {

  33. System.arraycopy(src,low,dest,low,high - low + 1);

  34. }

  35.  

  36. //src[low .. mid] + src[mid+1 .. high] -> dest[low .. high]

  37. merge(src,dest,low,mid,high);

  38. }

  39.  

  40. private void merge(Comparable[] src,Comparable[] dest,int low,int mid,int high) {

  41.  

  42. for(int i = low,v = low,w = mid + 1; i <= high; i++) {

  43. if(w > high || v <= mid && lessThanOrEqual(src[v],src[w])) {

  44. dest[i] = src[v++];

  45. }else {

  46. dest[i] = src[w++];

  47. }

  48. }

  49. }

 

数据太多,递归太深 ->栈溢出?加大Xss?数据太多,数组太长 -> OOM?加大Xmx?

 

耐心不足,没跑出来.而且要将这么大的文件读入内存,在堆中维护这么大个数据量,还有内排中不断的拷贝,对栈和堆都是很大的压力,不具备通用性。

sort命令来跑

跑了多久呢?24分钟.

为什么这么慢?

粗略的看下我们的资源:

内存 jvm-heap/stack,native-heap/stack,page-cache,block-buffer 外存 swap + 磁盘 数据量很大,函数调用很多,系统调用很多,内核/用户缓冲区拷贝很多,脏页回写很多,io-wait很高,io很繁忙,堆栈数据不断交换至swap,线程切换很多,每个环节的锁也很多.

总之,内存吃紧,问磁盘要空间,脏数据持久化过多导致cache频繁失效,引发大量回写,回写线程高,导致cpu大量时间用于上下文切换,一切,都很糟糕,所以24分钟不细看了,无法忍受.

位图法

 
  1. privateBitSet bits;

  2.  

  3. publicvoid perform(

  4. String largeFileName,

  5. int total,

  6. String destLargeFileName,

  7. Castor<Integer> castor,

  8. int readerBufferSize,

  9. int writerBufferSize,

  10. boolean asc) throwsIOException {

  11.  

  12. System.out.println("BitmapSort Started.");

  13. long start = System.currentTimeMillis();

  14. bits = newBitSet(total);

  15. InputPart<Integer> largeIn = PartFactory.createCharBufferedInputPart(largeFileName, readerBufferSize);

  16. OutputPart<Integer> largeOut = PartFactory.createCharBufferedOutputPart(destLargeFileName, writerBufferSize);

  17. largeOut.delete();

  18.  

  19. Integer data;

  20. int off = 0;

  21. try {

  22. while (true) {

  23. data = largeIn.read();

  24. if (data == null)

  25. break;

  26. int v = data;

  27. set(v);

  28. off++;

  29. }

  30. largeIn.close();

  31. int size = bits.size();

  32. System.out.println(String.format("lines : %d ,bits : %d", off, size));

  33.  

  34. if(asc) {

  35. for (int i = 0; i < size; i++) {

  36. if (get(i)) {

  37. largeOut.write(i);

  38. }

  39. }

  40. }else {

  41. for (int i = size - 1; i >= 0; i--) {

  42. if (get(i)) {

  43. largeOut.write(i);

  44. }

  45. }

  46. }

  47.  

  48. largeOut.close();

  49. long stop = System.currentTimeMillis();

  50. long elapsed = stop - start;

  51. System.out.println(String.format("BitmapSort Completed.elapsed : %dms",elapsed));

  52. }finally {

  53. largeIn.close();

  54. largeOut.close();

  55. }

  56. }

  57.  

  58. privatevoid set(int i) {

  59. bits.set(i);

  60. }

  61.  

  62. privateboolean get(int v) {

  63. return bits.get(v);

  64. }

nice!跑了190秒,3分来钟. 以核心内存4663M/32大小的空间跑出这么个结果,而且大量时间在用于I/O,不错.

问题是,如果这个时候突然内存条坏了1、2根,或者只有极少的内存空间怎么搞?

外部排序

该外部排序上场了. 外部排序干嘛的?

内存极少的情况下,利用分治策略,利用外存保存中间结果,再用多路归并来排序;

map-reduce的嫡系.

1.分

内存中维护一个极小的核心缓冲区memBuffer,将大文件bigdata按行读入,搜集到memBuffer满或者大文件读完时,对memBuffer中的数据调用内排进行排序,排序后将有序结果写入磁盘文件bigdata.xxx.part.sorted. 循环利用memBuffer直到大文件处理完毕,得到n个有序的磁盘文件:

2.合

现在有了n个有序的小文件,怎么合并成1个有序的大文件?把所有小文件读入内存,然后内排?(⊙o⊙)… no!

利用如下原理进行归并排序:

我们举个简单的例子:

文件1:3,6,9 文件2:2,4,8 文件3:1,5,7

第一回合:文件1的最小值:3 , 排在文件1的第1行 文件2的最小值:2,排在文件2的第1行 文件3的最小值:1,排在文件3的第1行 那么,这3个文件中的最小值是:min(1,2,3) = 1 也就是说,最终大文件的当前最小值,是文件1、2、3的当前最小值的最小值,绕么?上面拿出了最小值1,写入大文件.

第二回合:文件1的最小值:3 , 排在文件1的第1行 文件2的最小值:2,排在文件2的第1行 文件3的最小值:5,排在文件3的第2行 那么,这3个文件中的最小值是:min(5,2,3) = 2 将2写入大文件.

也就是说,最小值属于哪个文件,那么就从哪个文件当中取下一行数据.(因为小文件内部有序,下一行数据代表了它当前的最小值)

最终的时间,跑了771秒,13分钟左右.

 

总结:就是分治的思想,每次从大文件中取出固定的N个数,然后排序输出到一个小文件中,依次类推直到所有的数据都写入到文件中。然后多个小的文件进行多路归并merge,将多个小文件合并为一个大的有序的文件。多次合并之后数据就有序了。

下面给出一个leetcode上的两路归并的题:

将两个有序的数组合并到一个大的数组nums1中,前提是num1中的元素个数m很大,可以放下nums1+nums2的所有数据

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int index = m + n -1;while (n != 0) {if (m != 0 && nums1[m-1] > nums2[n-1]) {nums1[index--] = nums1[m-1];m--;} else if (0 == m || nums1[m-1] <= nums2[n-1]) {nums1[index--] = nums2[n-1];n--;}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463049.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jmeter连数据库

前提&#xff1a;jmeter不能直接连数据库&#xff0c;需要导入一个jar包 步骤&#xff1a; 1、右键线程组--添加--配置元件--JDBC Connection Configuration 2、jdbc的基本配置&#xff1a;可以修改jdbc配置的名称、随便填写变量名Variable Name&#xff0c;再填写最下面的数据…

设置窗口的光标,设置ToolBar,设置状态栏

代码 //ex_10Dlg.cpp : implementation file//#include "stdafx.h"#include "ex_10.h"#include "ex_10Dlg.h"#ifdef _DEBUG#definenew DEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[] __FILE__;#endif///////CAboutDlg dialog used for App Abo…

MySQL主从复制作用和原理

该文章是转载的&#xff0c;但是原文中有些描述的不准确&#xff0c;进行了修改。 一、什么是主从复制? 主从复制&#xff0c;是用来建立一个和主数据库完全一样的数据库环境&#xff0c;称为从数据库&#xff1b;主数据库一般是准实时的业务数据库。 二、主从复制的作用 1、…

windows mobile开发循序渐进(1)关于平台和工具

最近要进行windows mobile开发&#xff0c;很兴奋&#xff0c;因为之前对移动开发很感兴趣&#xff0c;并且做了一些B/S模式的开发&#xff0c;也做了一些包括WML和WEB移动开发的学习和开发&#xff0c;这次需要系统的整理一下windows mobile开发过程了&#xff0c;希望园子里的…

LC-BLSTM结构快速解读

参考文献如下&#xff1a; (1) A Context-Sensitive-Chunk BPTT Approach to Training Deep LSTM/BLSTM Recurrent Neural Networks for Offline Handwriting Recognition (2) Training Deep Bidirectional LSTM Acoustic Model for LVCSR by a Context-Sensitive-Chunk BPTT A…

spring boot 实战

https://windmt.com/2018/04/26/spring-cloud-full-reactive-microservices/ 这篇文章一级棒&#xff0c;实际操作一番&#xff0c;感觉有点理解微服务以及服务发现&#xff0c;服务间调用这几个概念。 但是对于响应式编程以及对于异步非阻塞场景等还是比较头大。 在实际操作中…

MySQL InnoDB的缓冲池之预读失效和缓存池污染

InnoDB的缓存池作用: 缓存表数据和索引数据,把磁盘上的数据加载到缓冲池中,避免每次都进行磁盘IO,起到加速访问的效果. LRU算法(Least recently used): 把入缓存池的页放在LRU的头部,作为最近访问的元素 页在缓冲池中的数据,把它放在队列的前面(情景一)页不在缓冲池中的数据,…

Hbase Rowkey设计原则

Hbase是三维有序存储的&#xff0c;通过rowkey&#xff08;行键&#xff09;,column key(column family和qualifier)和TimeStamp(时间戳)这三个维度可以对HBase中的数据进行快速定位。 Hbase中Rowkey可以唯一标识一行记录&#xff0c;在Hbase查询的时候&#xff0c;有以下几种方…

explicit关键字详解

C explicit关键字详解 首先, C中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式). 那么显示声明的构造函数和隐式声明…

Palm应用开发之四Palm 应用模型

本系列目录 Palm Web OS 简介 Palm 应用开发之一开发环境搭建 Palm 应用开发之二从Helloworld开始学习Palm开发Palm应用开发之三appinfo.json文件详解开发语言 应用使用的技术和Ajax使用的技术完全相似&#xff0c;palm webos 系统上建立应用没有专门的语言为其服务&#xff0c…

T-SQL 中ON和WHERE的区别

SQL中ON和WHERE的区别 数据库在通过连接两张或多张表来返回记录时&#xff0c;都会生成一张中间的临时表&#xff0c;然后再将这张临时表返回给用户。在使用left jion时&#xff0c;on和where条件的区别如下&#xff1a;1、 on条件是在生成临时表时使用的条件&#xff0c;它不管…

luogu3830 [SHOI2012]随机树

传送门&#xff1a;洛谷 题目大意&#xff1a;对于一个只有一个节点的二叉树&#xff0c;一次操作随机将这棵树的叶节点的下方增加两个节点。$n-1$次操作后变为$n$个叶节点的二叉树。求&#xff1a;&#xff08;1&#xff09;叶节点平均深度的期望值&#xff08;2&#xff09;树…

Mysql binlog应用场景与原理深度剖析

本文深入介绍Mysql Binlog的应用场景&#xff0c;以及如何与MQ、elasticsearch、redis等组件的保持数据最终一致。最后通过案例深入分析binlog中几乎所有event是如何产生的&#xff0c;作用是什么。 1 基于binlog的主从复制 Mysql 5.0以后&#xff0c;支持通过binary log(二进…

数据库中间件详解

本文是转载的文章&#xff0c;原文链接&#xff1a;https://mp.weixin.qq.com/s?__bizMzA5MDA5Njk0NQ&mid2456618601&idx1&snc10839f1797e7be1ea41f005b57432df&chksm87897237b0fefb215dd74c28cf5b524984b8f50d2ef13293e37919774f1c51e36642e489ee38&scen…

读书笔记《集体智慧编程》Chapter 5 : Optimization

本章概要 本章介绍了优化问题的基本概念&#xff0c;以及常见的优化算法&#xff08;随机搜索&#xff0c;爬山&#xff0c;模拟退火&#xff0c;遗传算法&#xff09;。读完本章后&#xff0c;感觉茅塞顿开&#xff0c;之前一直认为遗传算法高深莫测&#xff0c;原来这些算法都…

第五章· MySQL数据类型

一.数据类型介绍二.列属性介绍一.数据类型介绍 1.四种主要类别&#xfffc;1&#xff09;数值类型2&#xff09;字符类型3&#xff09;时间类型4&#xff09;二进制类型 2.数据类型的 ABC 要素1&#xff09;Appropriate&#xff08;适当&#xff09;2&#xff09;Brief&#xf…

深入浅出Android:初识Intent(BMI)

1、strings.xml 1 <?xml version"1.0" encoding"utf-8"?>2 <resources>3 4 <string name"app_name">BMI</string>5 <string name"height">身高(cm)</string>6 <string …

xcode10 自定义代码块

xcode10 之后自定义代码块已经不是10之前&#xff0c;直接将代码拖拽到代码块列表进行编辑了&#xff0c;10之后自定义代码块的方法&#xff0c;选择代码右键Create Code Snippet 在这里查看代码块 然后选中想要自定义的代码块&#xff0c;光标放在图标上&#xff0c;就会出现个…

解决虚拟机卡顿、卡死、待机后不动的情况(真实有效

本人环境&#xff1a; VM workstation 17.5 ubuntu 22.04 虚拟机配置&#xff1a;4核 4g issue&#xff1a; 出现开机卡死不动运行一段时间&#xff0c;可能半小时不到&#xff0c;就页面卡死不动经常需要关机重启才解决&#xff0c;可能没有解决 1.配置虚拟化引擎 这一步我称…

Parquet格式描述

背景 2010年 google 发表了一篇论文《Dremel: Interactive Analysis of Web-Scale Datasets》&#xff0c;介绍了其 Dermel 系统是如何利用列式存储管理嵌套数据的&#xff0c;嵌套数据就是层次数据&#xff0c;如定义一个班级&#xff0c;班级由同学组成&#xff0c;同学的信…