zoukankan      html  css  js  c++  java
  • 赫夫曼编码

    一、基础知识总结

    赫夫曼编码是一种变长编码。

    赋予高频词的字符较短的码字,低频次的字符较长的码字。

    所谓前缀码是没有任何码字是其他码字的前缀,使用前缀码使得在解码过程中更加简单无歧义。

    二叉树结构对于生成前缀码有特殊的优势,因为每一个叶节点到其他叶节点之间无关联,无法找到一个叶节点到其他叶节点的连续简单路径。

    这样的性质很好的满足和前缀码的需求。

    构造赫夫曼树利用了贪心的算法思想,维护一个优先队列,队列中初始状态为单节点子树,节点的值为字符权重。

    每次从优先队列中挑出最小和次小元素,进行合并,合并后的局部根节点为两子节点的值之和,然后把该合并后的子树加入优先队列中。

    重复以上过程直到优先队列中只剩一个元素,即为赫夫曼树的根节点。

    更一般的讲,该算法思想能够构造一棵具有n个叶节点的最小加权路径长度的二叉树。其中加权路径长度定义为:

    常见的应用常见比如:构造决策树。

    二、算法实现

    package aggreedy;
    import java.util.Comparator;
    import java.util.Deque;
    import java.util.PriorityQueue;
    
    public class HuffmanTree {
        // 树节点的数据结构
        static class Node {
            private int weight = 0;
            private Node left = null;
            private Node right = null;
            Node(int w){
                this.weight = w; 
            }
        }
        
        // 构造赫夫曼树
        public static Node createHuffmanTree(double[] w){
            
             Comparator<Node> cmp = new Comparator<Node>() {// 实例化比较器
                    @Override
                    public int compare(Node node1, Node node2) {
                        if (node2.weight > node1.weight) {
                            return -1;
                        }else if(node2.weight ==  node1.weight){
                            return 0;
                        }else {
                            return 1;
                        }
                    }
              };
            PriorityQueue<Node> queen = new PriorityQueue<Node>(10,cmp);
            for (int i = 0; i < w.length; i++) {// 初始状态为单节点子树
                queen.add(new Node((int)(w[i]*100)));
            }
            Node tmpNode1,tmpNode2,tmpMerge;
            while(queen.size()>1){
                // 取出优先队列中最小和次小的元素,合并成新的子树,并加入队列
                tmpNode1 = queen.poll();
                tmpNode2 = queen.poll();
                tmpMerge = new Node(tmpNode1.weight + tmpNode2.weight);
                tmpMerge.left = tmpNode1;
                tmpMerge.right = tmpNode2;
                queen.add(tmpMerge);
            }
            return queen.poll();
        }
        // 先序遍历赫夫曼树
        public static void preTravel(Node node){
            if (node != null) {
                System.out.println(node.weight);
                preTravel(node.left);
                preTravel(node.right);
            }
        }
        // 工具方法,判定是否为叶节点
        private static boolean isLeaf(Node node){
            return (node.left == null) && (node.right == null);
        }
        
        // 递归实现编码:左字数编码0,右子树编码为1
        private static void innerCode(Node node,String code){
            if (!isLeaf(node)) {
                StringBuilder tmpCode1 = new StringBuilder(code);
                if (node.left != null) {
                    tmpCode1.append("0");
                }
                innerCode(node.left, tmpCode1.toString());
                StringBuilder tmpCode2 = new StringBuilder(code);
                if (node.right != null) {
                    tmpCode2.append("1");
                }
                innerCode(node.right, tmpCode2.toString());
            }else {
                System.out.println(code);
            }
        }
        public static void code(Node node){// 根据赫夫曼树进行编码
            innerCode(node, "");
        }
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            double[] ary = {0.15,0.10,0.30,0.20,0.20,0.05};
    //        double[] ary = {0.10,0.15,0.20,0.20,0.35};
            Node root = createHuffmanTree(ary);
    //        preTravel(root);
            code(root);
        }
    }

     三、参考资料

    1、算法导论.第十六章

    2、算法设计与分析基础.第九章

  • 相关阅读:
    iOS input被键盘遮挡
    js解析xml出现的问题总结
    Java——操作Excel表格,读取表格内容
    进销存管理系统——代码架构
    转换机和路由器工作原理
    考勤系统代码分析——主页布局easyui框架
    考勤系统——代码分析datagrid
    测试知识整理——基础篇
    Base64编码原理分析
    考勤系统——代码分析
  • 原文地址:https://www.cnblogs.com/qcblog/p/7818721.html
Copyright © 2011-2022 走看看