大数据排序,理论上支持个100亿条没问题吧,o(∩_∩)o 哈哈 --给爱吃大肉包补充了注释

来源:互联网 发布:互换身体的网络电影 编辑:程序博客网 时间:2024/06/10 21:21

爱吃大肉包在文章《大数据排序,理论上支持个100亿条没问题吧,o(∩_∩)o 哈哈》中给出了一个大数据排序的源码。经过运行,成功了。

万恶的是,这人没写注释,读起来很不方便,因此,在自己机器上添加了注释后 ,上传上来。

做了一些小改动,

①为了可以重复测试,增加了删除目录下的所有文件的方法

②增加了计算耗时的方法

③增加了System.out.println();的方法,打印最后的结果集(数据量小时可以直观的查看结果。)主要是便于理解这个思路。

文章的原路径是:http://www.oschina.net/code/snippet_867417_19341?p=2#comments 点击打开链接


问题来自《Programming Perl》

楔子: 问题:假设一个文件中有9亿条不重复的9位整数,现在要求对这个文件进行排序。
一般解题思路: 1、将数据导入到内存中 2、将数据进行排序 (比如插入排序、快速排序) 3、将排序好的数据存入文件
难题: 一个整数为4个字节即使使用数组也需要900,000,000 * 4byte = 3.4G内存对于32位系统,访问2G以上的内存非常困难,而且一般设备也没有这么多的物理内存将数据完全导入到内存中的做法不现实。
其他解决办法: 1、导入数据库运算 2、分段排序运算 3、使用bit位运算
解决方案一:数据库排序 将文本文件导入到数据库,让数据库进行索引排序操作后提取数据到文件
优点:操作简单缺点:运算速度慢,而且需要数据库设备。
解决方案二:分段排序 操作方式:规定一个内存大小,比如200M,200M可以记录52428800条记录,我们可以每次提取5000万条记录到文件进行排序,要装满9位整数需要20次,所以一共要进行20次排序,需要对文件进行20次读操作
缺点: 编码复杂,速度也慢(至少20次搜索)
关键步骤:先将整个9位整数进行分段,亿条数据进行分成20段,每段5000万条,在文件中依次搜索0~5000万,50000001~1亿…… 将排序的结果存入文件
解决方案三:bit位操作 思考下面的问题: 一个最大的9位整数为999999999 这9亿条数据是不重复的,可不可以把这些数据组成一个队列或数组,让它有0~999999999(10亿个)元素数组下标表示数值,节点中用0表示这个数没有,1表示有这个数,判断0或1只用一个bit存储就够了


下面是我添加注释后的代码 ,第二种思路

import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.FilenameFilter;import java.io.IOException;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Random;/** *  * @author Hejinbin QQ 277803242 email qing878@gmail.com */public class BigDataSort {public final static String SMALL_FILE_PATH = "e://temp//BigData//";public final static int BIG_NUM_LINE = 1000000;// 务必保证BIG_NUM_LINE 是// SMALL_FILE_LINE的倍数public final static String ORING_FILE_PATH = "e://temp//BigData//bigData.txt";public final static int SMALL_FILE_LINE = 100000; // 1M for 1 small fileprivate File tempFiles[];public BigDataSort() throws IOException {// 补充方法 删除所有文件deleteAllFile();// 删除所有的。temp文件deleteAlltempFile();// 将BIG_NUM_LINE条int值,放到指定的文件ORING_FILE_PATH中,每行一个createBigsortNums();// 拆分成小文件排序,(需要明确计算出小文件的大小不能超出可用内存)【编程珠玑 programming perl】中的问题beSmallFileAndSort();unitFileToSort();}private void createBigsortNums() throws IOException {BufferedWriter writer = new BufferedWriter(new FileWriter(ORING_FILE_PATH));Random random = new Random();for (int i = 0; i < BIG_NUM_LINE; i++) {writer.write(String.valueOf(random.nextInt(100000000)));writer.newLine();// add a new line . in order to show easy by file}writer.close();}private void beSmallFileAndSort() throws IOException {BufferedReader bigDataFile = new BufferedReader(new FileReader(ORING_FILE_PATH));List<Integer> smallLine = null;String str = "";// 根据大文件和小文件的数量,生成n个小文件int fileCount = BIG_NUM_LINE / SMALL_FILE_LINE;tempFiles = new File[fileCount];for (int i = 0; i < tempFiles.length; i++) {tempFiles[i] = new File(SMALL_FILE_PATH + "sortTempFile" + i+ ".temp");BufferedWriter smallWtite = new BufferedWriter(new FileWriter(tempFiles[i]));smallLine = new ArrayList<Integer>();// 向n个文件中插入字符串,每个文件长度为small_file_line,最后一个装入剩余数量for (int j = 0; j < SMALL_FILE_LINE; j++) {smallLine.add(Integer.parseInt(bigDataFile.readLine()));}// 使用Collections的排序Collections.sort(smallLine);// 逐行写入文件for (Object num : smallLine.toArray()) {smallWtite.write(num + "\n");}// 每写完一个文件,需要将IO流关闭smallWtite.close();}}private void unitFileToSort() throws IOException {File tempFile = null;// 以第一个文件为基准,其余的文件向第一个文件写入临时文件for (int i = 1; i < tempFiles.length; i++) {tempFile = sortBySmallFile(tempFiles[0], tempFiles[i]);// 删除第一个文件tempFiles[0].delete();// 将合并后的临时文件放入第一个文件中,此时,第一个文件已经是0,...i个文件的合并后的结果tempFiles[0] = tempFile;}tempFile.renameTo(new File(ORING_FILE_PATH + "sortResult.txt"));BufferedReader br = new BufferedReader(new FileReader(new File(ORING_FILE_PATH + "sortResult.txt")));// String str = "";// while (null != (str = br.readLine())) {// System.out.println(str);// }打印比较耗时br.close();}/** *  * @param fromFile *            第一个文件 A (为了便于注释,将文件命名为 A 、B ,结果文件命名为C) * @param toFile *            第二个文件 B * @return * @throws IOException */public static File sortBySmallFile(File fromFile, File toFile)throws IOException {BufferedReader fromRd = new BufferedReader(new FileReader(fromFile));BufferedReader toTempRd = new BufferedReader(new FileReader(toFile));// 临时的排序的结果文件 CFile newSortFile = new File(SMALL_FILE_PATH + fromFile.getName()+ ".temp");// File newSortFile = new File(SMALL_FILE_PATH + "sortTempFile.temp");BufferedWriter newSortFileWt = new BufferedWriter(new FileWriter(newSortFile));int index = -1;int toPoint = -1;// 【1-0】判断此流是否已准备好被读取。如果缓冲区不为空,或者底层字符流已准备就绪,则缓冲的字符流准备就绪。while (fromRd.ready()) {index = Integer.parseInt(fromRd.readLine());if (index < toPoint) {// 【1-1】 第一个文件A中的数值 小于 第二个文件B的数值,将第一个文件数值写入C,newSortFileWt.write(String.valueOf(index));newSortFileWt.newLine();// 跳出此次循环,进入下一个循环continue;} else {// 【1-2】 第一个文件A中的数值 大于 第二个文件B的数值,(-1时,首次读取B中的数值)将第二个文件数值写入C,if (toPoint != -1) {newSortFileWt.write(String.valueOf(toPoint));newSortFileWt.newLine();}// 继续读取第二个文件中的数值}while (toTempRd.ready()) {// 【2-0】 读取第二个文件中的数值toPoint = Integer.parseInt(toTempRd.readLine());if (toPoint < index) {// 【2-1】 第二个文件B中的数值 小于// 第一个文件A的数值,(先读的A,因此,index不肯为-1)将第二个文件数值写入C,newSortFileWt.write(String.valueOf(toPoint));newSortFileWt.newLine();// 继续读取第二个文件} else {// 【2-2】 第二个文件B中的数值 大于 第一个文件A的数值, 将第一个文件数值写入C,newSortFileWt.write(String.valueOf(index));newSortFileWt.newLine();// 停止读取第二个文件B的while循环break;}}// 隐藏的逻辑:当A先读完,则B中的数值为较大数值,第二层的while语句会将B中的数值读出并写入C// 若B先读完,A中的值较大,则执行注释中的【1-2】部分的代码,因为B文件已读完,toTempRd.ready()为false,不在执行【2-0】部分去读取B文件}newSortFileWt.write(String.valueOf(index > toPoint ? index : toPoint));newSortFileWt.newLine();newSortFileWt.close();fromRd.close();toTempRd.close();// toFile.delete();return newSortFile;}private void deleteAllFile() {File f = new File(SMALL_FILE_PATH);File[] files;if (f.isDirectory()) {files = f.listFiles();for (File var : files) {var.delete();}}}private void deleteAlltempFile() {File f = new File(SMALL_FILE_PATH);File[] files;if (f.isDirectory()) {// 获取.temp结尾的文件files = f.listFiles(new FilenameFilter() {public boolean accept(File dir, String name) {if (name.endsWith(".temp")) {return true;}return false;}});for (File var : files) {var.delete();}}}public static void main(String[] args) throws IOException {Long before = System.currentTimeMillis();BigDataSort bigDataSort = new BigDataSort();Long after = System.currentTimeMillis();System.out.println("共耗用 " + (after - before) + " 毫秒");// 1000000 100000共耗用 2575 毫秒// 10000000 1000000共耗用 共耗用 21510 毫秒// 推论, 100亿,20000秒}// 一般分成10个文件后,需要19个临时小文件然后删除,确实挺高潮....}



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 儿子四岁脾气特别大怎么办呢 月子里屁股被开水烫了怎么办 学生打闹家长只找老师责任怎么办 两个学生打闹受伤的孩子家长怎么办 小孩学习不好做家长的该怎么办 对学习不入门的小孩家长该怎么办 孩子老做作业发神上课不专心怎么办 儿子成绩考得差不专心未来怎么办 五年级学生写字慢又丑怎么办 宝宝上课坐不住不听老师话怎么办 三岁宝宝特调皮打他还还手怎么办 怀孕40天不知道喝酒了怎么办 怀孕四十天的时候喝酒抽烟了怎么办 宝宝怀孕三十天左右喝酒了怎么办 两个人都喝酒了意外怀孕怎么办 不知道自己怀孕了喝了很多酒怎么办 不知道自己怀孕了喝了一次酒怎么办 我儿子11岁了有多动症怎么办 面对老师的冷暴力家长该怎么办? 面对无德的老师家长该怎么办 如果你家长屏蔽老师老师该怎么办 小孩出完水痘后身上出现疱疹怎么办 脑子里兴奋的头疼怎么办 吃什么药 一个月宝宝异常兴奋不睡觉怎么办 四个月宝宝晚上兴奋不睡觉怎么办 20个月宝宝半夜惊醒哭闹怎么办 小孩吃了氨茶碱兴奋不睡觉怎么办 孩子在学校被同学撞鼻骨折怎么办 孩子在学校无意致使同学受伤怎么办 9个月的宝宝吃坏东西腹泻怎么办 8个月发烧到38度怎么办 1岁半宝宝鼻塞发烧38度6怎么办 八个月的宝宝发热38度怎么办 八个月宝宝发热在38度怎么办 8个月孩子发烧38度怎么办 6个月孩子发烧38度多怎么办 7个月孩子发烧38度怎么办 小明上课总是东张西望你该怎么办 初中二年级贪玩游戏说不听怎么办 孩子上课经常和别的同学说话怎么办 小孩五年级了上课坐不住怎么办