您当前的位置:首页 > 新闻 > 科技

今日头条面试题:5亿数值大文件如何排序?

时间:2020-03-12 12:19:32  来源:  作者:

最近,面试头条,面试官一上来,就问了我这么一个问题,我一脸懵逼,决定记录一下。

问题

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

6196302
3557681
6121580
2039345
2095006
1746773
7934312
2016371
7123302
8790171
2966901
...
7005375 

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

内部排序

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

3路快排:

private final int cutoff = 8;

public <T> void perform(Comparable<T>[] a) {
    perform(a, 0, a.length - 1);
}

private <T> int median3(Comparable<T>[] a, int x, int y, int z) {
 if (lessThan(a[x], a[y])) {
 if (lessThan(a[y], a[z])) {
 return y;
 } else if (lessThan(a[x], a[z])) {
 return z;
 } else {
 return x;
 }
 } else {
 if (lessThan(a[z], a[y])) {
 return y;
 } else if (lessThan(a[z], a[x])) {
 return z;
 } else {
 return x;
 }
 }
}

private <T> void perform(Comparable<T>[] a, int low, int high) {
 int n = high - low + 1;
 // 当序列非常小,用插入排序
 if (n <= cutoff) {
 InsertionSort insertionSort = SortFactory.createInsertionSort();
        insertionSort.perform(a, low, high);
 // 当序列中小时,使用median3
 } else if (n <= 100) {
 int m = median3(a, low, low + (n >>> 1), high);
        exchange(a, m, low);
 // 当序列比较大时,使用ninther
 } else {
 int gap = n >>> 3;
 int m = low + (n >>> 1);
 int m1 = median3(a, low, low + gap, low + (gap << 1));
 int m2 = median3(a, m - gap, m, m + gap);
 int m3 = median3(a, high - (gap << 1), high - gap, high);
 int ninther = median3(a, m1, m2, m3);
        exchange(a, ninther, low);
 }

 if (high <= low)
 return;
 // lessThan
 int lt = low;
 // greaterThan
 int gt = high;
 // 中心点
 Comparable<T> pivot = a[low];
 int i = low + 1;

 /*
        * 不变式:a[low..lt-1] 小于pivot -> 前部(first) a[lt..i-1] 等于 pivot -> 中部(middle)
        * a[gt+1..n-1] 大于 pivot -> 后部(final)
        *
        * a[i..gt] 待考察区域
        */

 while (i <= gt) {
 if (lessThan(a[i], pivot)) {
 // i-> ,lt ->
            exchange(a, lt++, i++);
 } else if (lessThan(pivot, a[i])) {
            exchange(a, i, gt--);
 } else {
            i++;
 }
 }

 // a[low..lt-1] < v = a[lt..gt] < a[gt+1..high].
    perform(a, low, lt - 1);
    perform(a, gt + 1, high);
} 

归并排序:

/**
 * 小于等于这个值的时候,交给插入排序
 */
private final int cutoff = 8;

/**
 * 对给定的元素序列进行排序
 *
 * @param a 给定元素序列
 */
@Override
public <T> void perform(Comparable<T>[] a) {
 Comparable<T>[] b = a.clone();
    perform(b, a, 0, a.length - 1);
}

private <T> void perform(Comparable<T>[] src, Comparable<T>[] dest, int low, int high) {
 if (low >= high)
 return;

 // 小于等于cutoff的时候,交给插入排序
 if (high - low <= cutoff) {
 SortFactory.createInsertionSort().perform(dest, low, high);
 return;
 }

 int mid = low + ((high - low) >>> 1);
    perform(dest, src, low, mid);
    perform(dest, src, mid + 1, high);

 // 考虑局部有序 src[mid] <= src[mid+1]
 if (lessThanOrEqual(src[mid], src[mid + 1])) {
 System.arraycopy(src, low, dest, low, high - low + 1);
 }

 // src[low .. mid] + src[mid+1 .. high] -> dest[low .. high]
    merge(src, dest, low, mid, high);
}

private <T> void merge(Comparable<T>[] src, Comparable<T>[] dest, int low, int mid, int high) {

 for (int i = low, v = low, w = mid + 1; i <= high; i++) {
 if (w > high || v <= mid && lessThanOrEqual(src[v], src[w])) {
            dest[i] = src[v++];
 } else {
            dest[i] = src[w++];
 }
 } 
} 

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

数据太多,数组太长 -> OOM?加大Xmx?

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

sort命令来跑

跑了多久呢?24分钟。

为什么这么慢?

粗略的看下我们的资源:

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

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

位图法

private BitSet bits;

public void perform(String largeFileName, int total, String destLargeFileName, Castor<Integer> castor,
 int readerBufferSize, int writerBufferSize, boolean asc) throws IOException {

 System.out.println("BitmapSort Started.");
 long start = System.currentTimeMillis();
    bits = new BitSet(total);
 InputPart<Integer> largeIn = PartFactory.createCharBufferedInputPart(largeFileName, readerBufferSize);
 OutputPart<Integer> largeOut = PartFactory.createCharBufferedOutputPart(destLargeFileName, writerBufferSize);
    largeOut.delete();

 Integer data;
 int off = 0;
 try {
 while (true) {
            data = largeIn.read();
 if (data == null)
 break;
 int v = data;
 set(v);
            off++;
 }
        largeIn.close();
 int size = bits.size();
 System.out.println(String.format("lines : %d ,bits : %d", off, size));

 if (asc) {
 for (int i = 0; i < size; i++) {
 if (get(i)) {
                    largeOut.write(i);
 }
 }
 } else {
 for (int i = size - 1; i >= 0; i--) {
 if (get(i)) {
                    largeOut.write(i);
 }
 }
 }

        largeOut.close();
 long stop = System.currentTimeMillis();
 long elapsed = stop - start;
 System.out.println(String.format("BitmapSort Completed.elapsed : %dms", elapsed));
 } finally {
        largeIn.close();
        largeOut.close();
 }
}

private void set(int i) {
    bits.set(i);
}

private boolean get(int v) {
 return bits.get(v);
} 

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

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

外部排序

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

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

map-reduce的嫡系。

今日头条面试题:5亿数值大文件如何排序?

 


今日头条面试题:5亿数值大文件如何排序?

 

1、分

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

今日头条面试题:5亿数值大文件如何排序?

 

2、合

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

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

今日头条面试题:5亿数值大文件如何排序?

 

我们举个简单的例子:

文件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分钟左右。

less bigdata.sorted.text
...
9999966
9999967
9999968
9999969
9999970
9999971
9999972
9999973
9999974
9999975
9999976
9999977
9999978
... 

更多面试资料分享

今日头条面试题:5亿数值大文件如何排序?


Tags:   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言什么是数据脱敏数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护常用脱敏规则替换、重排、加密、截断、掩码良好的数据脱敏实施1、尽...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
河南最有名的“13碗面”,吃过10种以上的一定是地道河南人,你吃过几碗?河南位于黄河中下游,优越的地理位置和条件,让河南的种植业在全国脱颖而出,被称为全国的“粮仓”。小麦是河南...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
在狗界中,有些狗狗比较凶残、霸道,今天我们就来说说被称为“犬中四煞”的4种狗,请认住它们的长相,看见了要绕路走! NO1:黑狼犬产地:中国寿命:11-12年黑狼犬是狼狗的一种,长大高大威猛...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
协议下的体面离婚 2015年1月 方晴供职于一家外企,袁亮硕士毕业后开了家公司。两人相识、恋爱后走进婚姻殿堂。 方晴和袁亮的儿子小浩出生了。本该是其乐融融的三口之家,却在一...【详细内容】
2021-12-28  Tags:   点击:(2)  评论:(0)  加入收藏
中国人神话世界五千年到一万年之前到底是一个什么样的世界?相信这个问题应该是困扰了大家许久吧!其实这些问题可以从远古时代的三皇五帝开始说起,三皇五帝对于中国人的影响就如...【详细内容】
2021-12-28  Tags:   点击:(2)  评论:(0)  加入收藏
去年有个新闻,说的是一名印度女孩自小被欧洲有钱人家收养,长大后要回来给自己出生的村子捐钱做慈善。等她回村的时候,村里人专门为女孩修了一条路。表面上看,这貌似是个暖心的故...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
日本在今年又给大家带来了一个巨大消息,日本著名的球星本田圭佑出资设立的一家公司,正式发售了飞行摩托车。 在之前可是在电视或者是电影中才能看到的,是具备了未来科幻的一个...【详细内容】
2021-12-28  Tags:   点击:(4)  评论:(0)  加入收藏
V社今日公布了2021年Steam最畅销游戏榜单,其中涵盖了本年度Steam上收入最高的100款游戏。为了得出每款游戏的总收入,Steam计算了2021年1月1日至2021年12月15日的游戏销售额、...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
“都怪我一时糊涂铸下大错,这几年为了蒙混过关,拆东墙补西墙就怕被发现,我对不起信任我的领导同事,更对不起我的家人。”内蒙古某国有合资公司原出纳员包某在庭审现场听取公诉人...【详细内容】
2021-12-28  Tags:   点击:(2)  评论:(0)  加入收藏
2021年黄金价格下跌11.3%,黄金现在已经下跌了6.5%。白银价格一度下跌19.3%,白银现在已经下跌了15%。美元通胀。白银自2020年2月份以来,五家中央银行(Fed、欧洲中央银行、日本中...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
▌简易百科推荐
非法购买公民信息、开发人脸认证规避技术&hellip;&hellip;今年年初,广东省公安厅网安部门侦破全国首例破解“青少年防沉迷系统”的新型网络犯罪案件,抓获犯罪嫌疑人13名,查处非...【详细内容】
2021-12-28    人民日报客户端  Tags:数据安全步   点击:(5)  评论:(0)  加入收藏
就在今天,腾讯方面宣布将在2022年1月31日下架企业QQ和营销QQ,其实这一消息的降临并不让笔者意外,因为早在今年的10月28日20点之后,企业QQ和营销QQ就被停止了续费服务。相信很多...【详细内容】
2021-12-27  科技探险家    Tags:企业QQ   点击:(21)  评论:(0)  加入收藏
日前,上海交通大学发布《全球电竞之都评价报告》,对全球15个致力于发展电竞之都的城市进行评价,上海作为中国城市电竞发展的排头兵,其拥有众多优质电竞企业及完整产业集群,因此排...【详细内容】
2021-12-27  经济日报    Tags:电竞   点击:(3)  评论:(0)  加入收藏
为优化网络氛围环境,微博又开始整顿用户信息了。本月月初,微博官方发布公告,要求昵称中带有如“二货”“SB”“瘪三”“娘炮”等明显低俗或侮辱性词汇的用户尽快修改,否则将面临...【详细内容】
2021-12-24  运了个营    Tags:微博   点击:(10)  评论:(0)  加入收藏
昨日谷歌宣布,自2022年12月19日开始停止对OnHub的软件支持,OnHub路由器仍将提供Wi-Fi信号,但用户无法用谷歌Home应用程序管理它。无法更新Wi-Fi网络设置、添加额外的Wifi设备或...【详细内容】
2021-12-22  雷峰网    Tags:Google OnHub   点击:(5)  评论:(0)  加入收藏
IT之家 12 月 20 日消息,百度网盘青春版 iOS 客户端今日晚间率先开启内测,安卓客户端将在稍后内测。使用苹果 iPhone 的IT之家小伙伴可以点此下载内测版,需要先下载 TestFlight...【详细内容】
2021-12-21  IT之家    Tags:百度网盘   点击:(10)  评论:(0)  加入收藏
对于拼车单,是接还是不接,不少网约车司机表示很矛盾。接吧,钱少事多,常常跑了个寂寞,不接吧,车多客少,挑三拣四没饭吃。 在平台大力推广拼车单之下,不少司机迫于生活压力,最终还是打...【详细内容】
2021-12-17  网约车情报分享    Tags:滴滴   点击:(9)  评论:(0)  加入收藏
蓝鲸TMT频道12月16日讯,据饿了么官方微信公众号,近日,在圆桌会上,蓝骑士与平台交流了配送安全问题。饿了么表示,线上将技术手段融入安全防护;线下将持续进行安全培训,并试点智能头...【详细内容】
2021-12-17    金融界  Tags:饿了么   点击:(24)  评论:(0)  加入收藏
开源最前线(ID:OpenSourceTop) 猿妹编译项目地址: https://github.com/restic/restic全球知名代码托管平台 GitHub 今天就重磅发布了今年的年度报告&mdash;&mdash;《2021 年度 O...【详细内容】
2021-12-17  Python部落    Tags:   点击:(9)  评论:(0)  加入收藏
新京报快讯 据中国网络视听节目服务协会网站消息,12月15日,中国网络视听节目服务协会发布了《网络短视频内容审核标准细则》(2021)。中国网络视听节目服务协会组织有关短视频平...【详细内容】
2021-12-16    新京报  Tags:短视频   点击:(11)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条