27 电话号码排序

前言

本博文部分图片, 思路来自于剑指offer 或者编程珠玑

这部分来自于编程珠玑, “编程珠玑”就是从这个例子开始的, 我看了过后, 感觉非常有意思啊, 觉得能够冲这本书中学到很多东西
不过 后来看完之后, 又过了几个月, 便基本上快要忘光了…
可能是对于 这本书敲的代码不多吧, 很多问题在前面的几本书中出现过
这本书敲的代码 似乎仅仅4, 5个
而且 部分章节十分注理论的描述, so 忘记了..

问题描述

27 电话号码排序_第1张图片

27 电话号码排序_第2张图片

思路

思路一 : 使用外部排序, 分批加载到内存排序, 输出, 合并

思路二 : 四十个”线程”[我没有理解到”通道”的含义, 我的理解为线程]对于 四十批数据进行快速排序

思路三 : 输入的数据有两个特性, 第一 : 不重复, 因此 我们不用记录每一个数据的个数, 而只用记录该数字是否存在, 2. 数字固定在一个区间[0 - 9999999] [10000000 / 8 / 1024 / 1024 = 1.19], 根据上述的计算, 使用BitSet的话, 只需要1.19M [似乎 超出了一点啊]的内存就可以表示[0 - 9999999]
读取文件, 获取每一个数字, 将对应的位置为1, 读取完文件中所有的数据之后, 遍历一次BitSet, 输出到目标文件即可

思路二编程珠玑原图
27 电话号码排序_第3张图片

参考代码

: 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, 所以请大家指出!

你可能感兴趣的:(08,[剑指Offer,&,编程珠玑]_笔记)