学习笔记-算法-10-二叉树-2

28 篇文章 0 订阅
18 篇文章 0 订阅

赫夫曼树

  • 路径
  • 路径长度
  • 节点的权
  • 节点带权路径长度
  • 树的带权路径长度
    • wpl
    • 最小就叫赫夫曼树
public class Demo{

    // 遍历
    public static void preOrder(Node root){
        if(root!=null){
            root.preOrder();
        }else{
            System.out.println("空树");
        }
    }
    
    // 创建赫夫曼树
     public static Node createHuffmanTree(int[] arr){
        // 遍历arr
        // 将arr构成Node
        // 将node放入ArrayList
        List<Node> nods = new ArrayList<Node>();
        for(int value : arr){
            node.add(new Node(value))
        }
        while(nodes.size()>1){
             // 排序,从小到大
            Collections.sort(nodes);
            // 取出根节点权值最小的二叉树
            // 取出全局最小的节点
            Node leftNode = nodes.get(0);
            // 取出第二小
            Node rightNode = nodes.get(1);
            // 构建新二叉树
            Node parent = new Node(leftNode.value+rightNode.value);
            parent.left = leftNode;
            praent.right = rightNode;
            
            // 从arrayList中删除处理过的二叉树
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            // 将parent加入nodes
            nodes.add(parent);
        }
        return nodes.get(0);
    }
}

// 创建节点类
// 实现Compareable 利于排序
class Node implements Compareable<Node>{
    int value;// 节点权
    Node left;// 左子节点
    Node right;// 右子节点
    public Node(int value){
        this.value = value;
    }
    
    public int compareTo(Node o){
        // 从小到大排序
        return this.value - o.value;
    }
    
    // 遍历
    public void preOrder(){
        System.out.println(this);
        if(this.left!=null){
            this.left.preOrder();
        }
        if(this.right!=null){
            this.reight.preOrder();
        }
    }
    
}

数据压缩

  • 赫夫曼编码
public class HuffmanCode{
    // 将赫夫曼编码存放到Map<Byte,String>
    static Map<Byte,String> huffmanBCodes = new HashMap<Byte,String>();
    // 生成哈夫曼编码表,需要字符串拼接
    static StringBuilder stringBuilder = new StringBuilder();

    public static void main(String[] args){
        String content = "xxxxxxxxxxxxxxxxxxxxx";
        byte[] contentBytes = content.getBytes();
        List<Node> nodes = getNodes(contentBytes);
        Node huffmanTreeRoot = createHuffman(nodes);
        preOrder(huffmanTreeRoot);
        
        // 生成对应赫夫曼编码
        Map<Byte,String> huffmanCodes = getCodes(huffmanTreeRoot);
        
        byte[] huffmanCodeBytes = zip(contentBytes,huffmanCodes)
    }
    
    // 将压缩方法封装
    private static byte[] huffmanXip(byte[] bytes){
        List<Node> nodes = getNodes(bytes);
        // 创建huffman树
        Node huffmanTreeRoot = createHuffman(nodes);
        // 生成对应赫夫曼编码
        Map<Byte,String> huffmanCodes = getCodes(huffmanTreeRoot);
        // 压缩
        byte[] huffmanCodeBytes = zip(contentBytes,huffmanCodes)
        return huffmanCodeBytes;
    }
    
    
    // 将字符串对应的byte[] 通过赫夫曼编码,返回压缩后的byte[]
    private static byte[] zip(byte[] bytes,Map<byte,String> huffmanCodes){
        // 利用huffmanCodes 将bytes转成对应字符串
        StringBuilder stringBuilder = new StringBuilder();
        for(byte b : bytes){
            stringBuilder.append(hyffmanCodes.get(b));
        }
        
        // 统计返回的byte[] huffmanCodeBytes长度
        int len; // len =(stringBuilder.length()+7 )/8;
        if(stringBuilder.length%8==0){
            len = stringBuilder.length()/8;
        }else{
            len = stringBuilder.length()/8+1;
        }
        // 创建压缩后的byte数组
        byte[] huffmanCodeBytes = new byte[len];
        int index = 0;
        for(int i=0;i<stringBuilder.length();i+=8){
            String strByte;
            if(i+8>stringBuilder.length()){
                strByte = stringBuilder.subString(i)
            }else{
                strByte = stringBuilder.substring(i,i+8);
            }
           
            // 将strByte转化byte,并放入huffmanCodeBytes
            huffmanCodeBytes[index] = (byte)Integer.parseInt(strByte,2);
            index++;
        }
        return huffmanCodeBytes;
    }
    
    
    private static Map<Byte,String> getCodes(Node root){
        if(root==null){
            return null;
        }
        getCodes(root.left,"0",stringBuilder);
        getCOdes(root.right,"1",stringBuilder);
    }
    

    // 将传入的node的所有叶子节点的赫夫曼编码得到,并放入到huffmanBCodes
    // code 路径 左子节点0 右子节点1
    private static void getCodes(Node node,String code,StringBuilder stringBuilder){
        StringBuilder stringBulder2 = new StringBuilder(stringBuilder);
        stringBulder2.append(code);
        if(node!=null){
            // 当前node是叶子节点还是非叶子节点
            if(node.data==null){
                // 非叶子节点
                // 向左递归
                getCodes(node.left,"0",stringBuilder2);
                // 向右递归
                getCodes(node.right,"1",stringBuilder2);
            }else{
                // 叶子节点
                huffmanCodes.put(node.data,stringBuilder2.toString());
            }
            
        }
    }
    // 遍历
    public static void preOrder(Node root){
        if(root!=null){
            root.preOrder();
        }else{
            System.out.println("空");
        }
    }
    
    
    private static List<Node> getNodes(byte[] bytes){
        // 创建一个ArrayList
        ArrayList<Node> nodes = new ArrayList<Node>();
        
        // 遍历bytes,统计每个byte出现的次数
        Map<Byte,Integer> counts = new HashMap();
        for(byte b:bytes){
            Integer count = counts.get(b);
            if(count==null){
                counts.put(b,1);
            }else{
                counts.put(b,count+1);
            }
        }
        // 将map转成node
        for(Map.Entry<Byte,Integer> entry:counts.entrySet()){
            nodes.add(new Node(entry.getLKey(),entry.getValue()));
        }
        return nodes;
    }
    
    // 创建赫夫曼树
    private static Node createHuffman(List<Node> nodes){
        while(nodes.size()>1){
            Collections.sort(nodes);
            // 取出第一个最小
            Node leftNode = nodes.get(0);
            // 取出第二个
            Node rightNode = nodes.get(1);
            Node parent = new Node(null,leftNode.weight+rightNode.weight);
            parent.left = leftNode;
            parent.right = rightNode;
            // 删除
            nodes.remove(leftNode);
            nodes.remvoe(rightNode);
            nodes.add(parent);
        }
        return nodes.get(0);
    }
    
    // 生成赫夫曼树对应的赫夫曼编码
    
    
}

class Node{
    Byte data;// 存放数据本身
    int weight;// 权值,表示字符出现的次数
    Node left;
    Node right;
    public Node(Byte data,int weight){
        this.data = data;
        this.weight = weight;
    }
    
    public int compareTo(Node o){
        // 从小到大
        return this.weight - o.weight;
    }
    
    public String toString(){
        return "Node[data="+data+"weight="+weight+"]";
    }
    
    // 遍历
    public void preOrder(){
        System.out.println(this);
        if(this.left!=null){
            this.left.preOrder();
        }
        if(this.right != null ){
            this.right.preOrder();
        }
    }
}

解压

// 将huffmanCodeBytes转对应的二进制字符串
// 将二进制字符串对照编码表转化为原字符串

// huffmanCodes 编码表
// huffmanBytes 获得的字节数组
public static byte[] decode(Map<Byte,String> huffmanCodes,byte[] huffmanBytes){
    // 得到huffmanBytes对应的二进制字符串
    StringBuilder stringBuilder = new StringBuilder();
    for(int i=0;i<huffmanBytes.length;i++){
        // 判断是不是最后一个
        boolean flag = (i==huffmanBytes.length-1);
        stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));
    }
    // 将字符串按赫夫曼编码进行解码
    Map<String,Byte> map = new HashMap<String,Byte>();
    for(Map.Entry<Byte,String> entry:huffmanCodes.entrySet()){
        map.put(entry.getValue(),entry.getKey());
    }
    // 创建集合,存放byte
    List<Byte> list = new ArrayList<>();
    for(int i=0;i<stringBuilder.length();i++){
        int count = 1;
        boolean flag = true;
        Byte b = null;
        while(flag){
            // 取出一个'1' '0'
            String key = stringBuilder.substring(i,i+count);
            b = map.get(key);
            if(b==null){
                // 没有匹配到
                count++;
            }else{
                // 匹配到 
                flag = false;
            }
        }
        list.add(b);
        i+=count;
    }
    byte b = new byte[list.size];
    for(int i=0;i<b.length;i++){
        b[i] = list.get(i);
    }
    return b;
}


// 将一个byte转化为二进制字符串
// flag true 需要补高位 false 不需要
private static String byteToBitString(boolean flag,byte b){
    int temp = b;
    // 如果是正数,需要补高位
    if(flag){
        temp |= 256; // 按位或 256 1000 0000    
    }
    String str = Integer.toBinaryString(temp);// 返回二进制补码
    if(flag){
        return str.substring(str.length()-8);
    }else{
        return str;
    }
}

文件压缩

// srcFile 压缩前文件
// dstFile 压缩后文件
public static void zipFile(String srcFile,String dstFile){
    // 创建输出流
    OutputStream os = null;
    ObjectOutputStream = null;
    // 创建文件输入流
    FileInputStream is = null;
    try{
       
        is = new FileInputStream(srcFile);
        byte[] b = new byte[is.available()];
        // 读取文件
        is.read(b);
        // 文件压缩
        byte[] huffmanZip = huffmanZip(b);
        os = new FileOutputStream(dstFile);
        // 创建一个与文件输出流关联的ObjectOutputStream
        oos = new ObjectOutputStream(os);

        oos.writeObject(huffmanBytes);
        // 以对象流方式写入赫夫曼编码,以便恢复源文件
        oos.writeObject(huffmanCodes)
        
    }catch(Exception e){
        
    }finally{
        try{
            is.close();
            oos.close();
            os.clsoe();
        }catch(Exception e){
            
        }
    }
    
    
}

解压文件

public static void unZipFile(Sring zipFile,String dstFile){
    // 定义文件输入流
    InputStream is = null;
    // 定义一个对象输入流
    ObjectInputStream ois = null;
    // 文件输出流
    OutputStream os = null;
    
    try{
        // 创建文件输入流
        is = new FileInputStream(zipFile);
        oos = new ObjectInputStream(is);
        // 读取byte数组 huffmanBytes
        byte[] huffmanBytes = (byte[])ois.readObject();
        // 读取赫夫曼编码表
        Map<Byte,String> huffmanCodes = (Map<Byte,String>)ois.readObject();
        
        // 解码
        byte[] bytes = decode(huffmanCodes,huffmanBytes);
        // 将bytes数组写入目标文件
        os = new FileOutputStream(dsFile);
        // 写数据
        os.write(bytes);
        
    }catch(Exception e){
        
    }finally{
        try{
            os.close();
            ois.close();
            is.close();
        }catcah(Exception e){
            
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值