个人笔记-哈夫曼树核心原理编码

/**
 *
 * 哈夫曼树
 * 所有结点带权路径长度之和最小
 * 
 * 核心思想是:出现频率最高,权重最大的数据节点,分布在二叉树的最头部层级,减少检索深度。
 */

public class HuffmanTree {


    //根节点
    Node root;


    /**
     * 构建一棵哈夫曼树
     * 1,前提是排序  首先对传进来的数据进行从小到大排序
     * 2,从集合中找出最小的两个,然后相加,组成一个父节点
     * 3,删除取出的两个,把父节点放回集合,继续排序
     *
     *反复循环,直到集合元素为空,最后生成的父节点,作为根节点
     * @param datas
     * @return
     */
    public Node createHuffmanTree(List  datas){

        if(datas == null || datas.size() == 0)return null;

        if(datas.size() == 1){//只有一个数据,直接赋值为根节点,然后结束
            root = datas.get(0);
            return root;
        }


        while (datas.size() >1){//个数大于1,循环操作

            //开始排序:思考,为啥要用末尾呢,这样方便增删效率更高
            Collections.sort(datas);//排序完毕后,从大到小,按照权重值

            //集合末尾取出两个最小值,
            Node node1 = datas.get(datas.size() - 1);
            Node node2 = datas.get(datas.size() - 2);

            //开始创建父节点
            int parentWeight = node1.weight + node2.weight;

            Node parentNode = new Node("parent",parentWeight);

            parentNode.leftChild = node1;//建立左孩子关联
            node1.parent = parentNode;

            parentNode.rightChild = node2;//建立右孩子关联
            node2.parent = parentNode;


            //删除最小的node
            datas.remove(node1);
            datas.remove(node2);

            //将parent节点放入集合
            datas.add(parentNode);
        }


        //这一步可以和datas.size() == 0 合并,但是为了方便理解,先这样写了
        //退出循环后,集合里只剩下parentNode
        root = datas.get(0);

        return root;

    }


    /**
     * 打印哈夫曼树
     *
     * 打印出来顺序,按照权重大小输出,要求是横向一层层打印,那么二叉树前中后序遍历不再适用
     *
     *
     * 可以使用链表队列,不断的放入取出,实现打印
     */
    public void printTree(){

        if(root == null){
            System.out.println("空树");
           return;
        }
        LinkedList nodeLinkedList = new LinkedList<>();

        nodeLinkedList.add(root);
        while(!nodeLinkedList.isEmpty()){

            Node poll = nodeLinkedList.poll();

            System.out.println(poll.data+"==weight-"+poll.weight);
            if(poll.leftChild != null){
                Node leftChild = poll.leftChild;
                nodeLinkedList.add(leftChild);
            }

            if(poll.rightChild != null){
                Node rightChild = poll.rightChild;
                nodeLinkedList.add(rightChild);
            }
        }



    }


    /**
     * 获取哈夫曼码
     *
     * 核心思路: 在哈夫曼路径中,左孩子为0 ,右孩子为1
     * 从要编码的node 往上找parent,然后把路径码(0或者1) 存起来,使用栈,这样最后取得时候就是正序哈夫曼编码了
     * @param node
     * @return
     */
    public String getHuffmanCode(Node node){
        if(node == null){
            return "";
        }

        if(node.parent == null){
            return "0";//根节点时,暂定返回0
        }


        //创建一个栈存放01值
        Stack stack = new Stack();
        
        Node nodeTemp = node;
        while (nodeTemp.parent != null){
            if(nodeTemp == nodeTemp.parent.leftChild){
               stack.push("0");
            }else if(nodeTemp == nodeTemp.parent.rightChild){
               stack.push("1");
            }

            nodeTemp = nodeTemp.parent;

        }


        StringBuilder builder = new StringBuilder();

        while (!stack.empty()){
            builder.append(stack.pop());
        }

        return builder.toString();

    }
    

    /**
     * 利用compare
     * @param 
     */

    public static class  Node implements Comparable{
        T data;//数据域

        int weight;//权值

        Node leftChild;
        Node rightChild;
        Node parent;

        public  Node(T t,int weight){
            this.data = t;
            this.weight = weight;
        }

        /**
         * 反过来写,这样排序Collections.sort 排出来,为从大到小
         * @param o
         * @return
         */
        @Override
        public int compareTo(@NonNull Node o) {
            if(weight > o.weight){
                return -1;
            }else if(weight < o.weight){
                return 1;
            }
            return 0;
        }
    }
}

你可能感兴趣的:(全面学习数据结构与算法)