本博文部分图片, 思路来自于剑指offer 或者编程珠玑
这部分来自于编程珠玑, “编程珠玑”就是从这个例子开始的, 我看了过后, 感觉非常有意思啊, 觉得能够冲这本书中学到很多东西
不过 后来看完之后, 又过了几个月, 便基本上快要忘光了…
可能是对于 这本书敲的代码不多吧, 很多问题在前面的几本书中出现过
这本书敲的代码 似乎仅仅4, 5个
而且 部分章节十分注理论的描述, so 忘记了..
思路一 : 使用外部排序, 分批加载到内存排序, 输出, 合并
思路二 : 四十个”线程”[我没有理解到”通道”的含义, 我的理解为线程]对于 四十批数据进行快速排序
思路三 : 输入的数据有两个特性, 第一 : 不重复, 因此 我们不用记录每一个数据的个数, 而只用记录该数字是否存在, 2. 数字固定在一个区间[0 - 9999999] [10000000 / 8 / 1024 / 1024 = 1.19], 根据上述的计算, 使用BitSet的话, 只需要1.19M [似乎 超出了一点啊]的内存就可以表示[0 - 9999999]
读取文件, 获取每一个数字, 将对应的位置为1, 读取完文件中所有的数据之后, 遍历一次BitSet, 输出到目标文件即可
注 : 1 代码中只实现了思路三
2 代码中生成随机数据的时候, 假定不重复, 如果存在重复 忽略
/**
* file name : Test25BigFileSort.java
* created at : 4:51:26 PM Jun 10, 2015
* created by 970655147
*/
package com.hx.test05;
public class Test25BigFileSort {
// 参数, max 表示生成的数的个数, range 表示生成的数的范围
// space 表示空格
// numPerLine 每一行应该存储的数字的个数
static int MAX = 1000;
static int RANGE = 1000000;
static int CAP_LEFT_MOVE = 4;
static char SPACE = ' ';
static int numPerLine = 1 << 5, lineMask = numPerLine - 1;
// 实现大文件排序
public static void main(String []args) {
String path = System.getProperty("user.dir") + "\\tmp\\Test25BigFileSort.txt";
String tarPath = System.getProperty("user.dir") + "\\tmp\\Test25BigFileSortTar.txt";
try {
generateBigFile(path);
// readFromFile(path);
sortBigFile(path, tarPath);
} catch (IOException e) {
e.printStackTrace();
}
// String str = "7 65417 2699";
// Log.log(getLastSpace(str, 2));
}
// 对大文件的数据进行排序
// 创建一个BitSet[BitMap], 用于保存数据, 是否存在
// 然后读取输入文件, 逐行解析, 并设置响应的位为true
// 最后 将存在的数字, 输出到目标文件, 实现了排序
private static void sortBigFile(String path, String tarPath) throws IOException {
BitSet bs = new BitSet(RANGE);
resolve(path, bs);
Log.log("resolve data success ...");
writeResult(tarPath, bs);
Log.log("write data success ...");
}
// 将文件逐行解析
// 当然 这里一个String.split 会更简单
private static void resolve(String path, BitSet bs) throws NumberFormatException, IOException {
File tarFile = new File(path);
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(tarFile)) );
try {
String line = null;
while((line = br.readLine()) != null ) {
if(line.trim().length() == 0) {
continue ;
}
int idx = 0;
int first = 0, second = 0;
int idxMax = Tools.getLastSpace(line, 2, SPACE);
while(first < idxMax ) {
while(line.charAt(idx ++) != SPACE) ;
second = idx - 1;
int val = Integer.parseInt(line.substring(first, second) );
bs.set(val, true);
// Log.logWithoutLn(val + " ");
while(line.charAt(idx ++) == SPACE) ;
first = idx - 1;
}
// 统计最后一个数组
while(line.charAt(idx ++) != SPACE) ;
second = idx - 1;
int val = Integer.parseInt(line.substring(first, second) );
bs.set(val, true);
}
} finally {
if(br != null) {
br.close();
}
}
}
// 将结果输出文件
private static void writeResult(String tarPath, BitSet bs) throws IOException {
File tar = new File(tarPath);
Tools.createNewFile(tar);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tar) );
StringBuilder sb = new StringBuilder((numPerLine + 2) << CAP_LEFT_MOVE);
int cnt = 0;
try {
for(int i=0; iif(bs.get(i)) {
if((cnt & lineMask) == lineMask) {
sb.append("\r\n");
bos.write(sb.toString().getBytes() );
sb.setLength(0);
}
sb.append(i + " ");
cnt ++;
}
}
bos.write(sb.toString().getBytes() );
} finally {
if(bos != null) {
bos.close();
}
}
}
// 写出数据[写出MAX个范围为RANGE的随机数到path所在的文件中]
public static void generateBigFile(String path) throws IOException {
File tarFile = new File(path);
Tools.createNewFile(tarFile);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tarFile) );
try {
Random rand = new Random();
StringBuilder sb = new StringBuilder((numPerLine + 2) << CAP_LEFT_MOVE);
for(int i=0; i" ");
if((i & lineMask) == lineMask) {
sb.append(Tools.CRLF);
bos.write(sb.toString().getBytes());
sb.setLength(0);
}
}
bos.write(sb.toString().getBytes() );
} finally {
if(bos != null) {
bos.close();
}
}
Log.log("write data success ...");
}
// 读取path文件中的数据[BufferedReader]
public static void readFromFile(String path) throws IOException {
File tarFile = new File(path);
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(tarFile)) );
try {
String line = null;
while((line = br.readLine()) != null ) {
Log.log(line);
}
} finally {
if(br != null) {
br.close();
}
}
}
// 读取path文件中的数据[FileChannel]
public static void readFromFile02(String path) throws IOException {
File tarFile = new File(path);
FileChannel fc = Tools.getFileChannel(tarFile);
try {
ByteBuffer bBuf = ByteBuffer.allocate((numPerLine + 1) << CAP_LEFT_MOVE);
byte[] buff = new byte[((numPerLine + 1) << CAP_LEFT_MOVE)];
int readed = -1;
while((readed = fc.read(bBuf)) != -1) {
bBuf.flip();
bBuf.get(buff, 0, readed);
Log.log(new String(buff, 0, readed) );
}
} finally {
if(fc != null) {
fc.close();
}
}
}
}
Tools. getLastSpace(String str, int n, char tar)
// 获取倒数第"n个"空格 [连续的相同字符不算]
// 当然这里的鲁棒性存在问题 [while(str.charAt(-- i) == tar) ;]
public static int getLastSpace(String str, int n, char tar) {
int idx = -1;
int cnt = 0;
for(int i=str.length()-1; i>=0; i--) {
if(str.charAt(i) == tar) {
cnt ++;
if(cnt == n) {
idx = i;
break ;
}
while(str.charAt(-- i) == tar) ;
}
}
return idx;
}
大数据的处理 BitSet也是神器之一, 还有前面介绍的BloomFilter, 以及其他的数据结构
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!