Java数据结构--哈弗曼树

DEMO地址:
https://github.com/zhaopingfu/MDataStruct/blob/master/src/com/pf/%E6%A0%91/BintraySortTree.java

  • 1、路径和路径长度

    在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。

  • 2、结点的权及带权路径长度

    若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。

  • 3、树的带权路径长度

    树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。

带权路径长度最小的二叉树为哈弗曼树。

  • 哈弗曼树的构造

    1、先把有权值的叶子节点按照从小到大的顺序排列成一个有序序列,即:A5,E10,B15,D30,C40。
    2、取头两个最小权值的节点作为一个新的节点N1的两个子节点,注意相对较小的是左节点,这里就是A为N1的左节点,E为N1的右节点,如图所示,新节点的权值为两个叶子节点权值的和:5 + 10 = 15。
    《Java数据结构--哈弗曼树》
    3、将N1替换A与E,插入有序序列中,保持从小到大排列,即:N1 15,B15,D30,C40。
    4、重复步骤2。将N1与B作为一个新节点N2的两个子节点,N2的权值为:15 + 15 = 30。
    《Java数据结构--哈弗曼树》
    5、将N2替换N1与B,插入有序序列中。保持从小到大排列。即:N2 30,D30,C40。
    6、重复步骤2。将N2与D作为一个新节点N3的两个子节点,N3的权值为:30 + 30 = 60。
    《Java数据结构--哈弗曼树》
    7、将N3替换N2与D,插入有序序列中,保持从小到大排列。即:C40,N3 60。
    8、重复步骤2。将C与N3作为一个新节点T的两个字节点,由于T是根节点,所以哈弗曼树完成构造。
    《Java数据结构--哈弗曼树》

    /**
     * @author zhaopf
     * @version 1.0
     * @QQ: 1308108803
     * @date 2017年12月20日
     */
    public class TreeNode<T> {
    
        /**
         * 父节点
         */
        protected TreeNode<T> parent;
        /**
         * 左节点
         */
        protected TreeNode<T> leftChild;
        /**
         * 数据
         */
        protected T data;
        /**
         * 右节点
         */
        protected TreeNode<T> rightChild;
    
        public TreeNode() {
        }
    
        public TreeNode(T data) {
            if (data == null) {
                throw new IllegalArgumentException();
            }
            this.data = data;
        }
    
        /**
         * 添加节点
         *
         * @param data
         * @return
         */
        public TreeNode<T> put(T data) {
            throw new RuntimeException();
        }
    
        /**
         * 查找节点
         *
         * @param data
         * @return
         */
        public TreeNode<T> searchNode(T data) {
            throw new RuntimeException();
        }
    
        /**
         * 删除节点
         *
         * @param data
         * @return
         */
        public TreeNode<T> removeNode(T data) {
            TreeNode<T> node = searchNode(data);
            return removeNode(node) ? node : null;
        }
    
        /**
         * 删除一个节点
         *
         * @param node
         */
        public boolean removeNode(TreeNode<T> node) {
            throw new RuntimeException();
        }
    
        public TreeNode<T> getLeftChild() {
            return leftChild;
        }
    
        public void setLeftChild(TreeNode<T> leftChild) {
            this.leftChild = leftChild;
            if (leftChild != null) {
                leftChild.setParent(this);
            }
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public TreeNode<T> getRightChild() {
            return rightChild;
        }
    
        public void setRightChild(TreeNode<T> rightChild) {
            this.rightChild = rightChild;
            if (rightChild != null) {
                rightChild.setParent(this);
            }
        }
    
        public TreeNode<T> getParent() {
            return parent;
        }
    
        public void setParent(TreeNode<T> parent) {
            this.parent = parent;
        }
    }
    
    /**
     * @author zhaopf
     * @version 1.0
     * @QQ: 1308108803
     * @date 2017年12月24日
     * 哈弗曼树
     * <p>
     * 45(1) 90(1) 65(2) 85(2) 75(4)
     * 65(2) 85(2) T(2)  75(4)
     * T(2)  75(4)  T(4)
     * T(4)   T(6)
     * T(10)
     * <p>
     * ------------------T(10)
     * ----T(4)-----------------------T(6)
     * 65(2)    85(2)               T(2)        75(4)
     * ----------------------45(1)-------90(1)
     */
    public class HaffManTree<T>
            extends TreeNode<T>
            implements Comparable<HaffManTree<T>> {
    
        private static final String EMPTY_DATA = "**";
        /**
         * 根节点
         */
        private HaffManTree<T> root;
        /**
         * 权
         */
        private int weight;
    
        public HaffManTree(T data, int weight) {
            super(data);
            if (weight <= 0) {
                throw new IllegalArgumentException();
            }
            this.weight = weight;
            this.root = this;
        }
    
        /**
         * 添加一个节点
         * 相同数据的会筛掉(不是相同权)
         *
         * @param data   数据
         * @param weight 权
         * @return
         */
        public boolean put(T data, int weight) {
            if (data == null || weight <= 0) {
                return false;
            }
            // 拿到之前的节点
            Queue<HaffManTree<T>> queue = showHaffManTree(root);
            List<HaffManTree<T>> list = new ArrayList<>(Arrays.asList(new HaffManTree<>(data, weight)));
            if (queue != null && !queue.isEmpty()) {
                list.addAll(queue);
            }
            // 重新构造树
            createHaffManTree(list);
            return true;
        }
    
        @Override
        public HaffManTree<T> removeNode(T data) {
            if (data == null) {
                throw new IllegalArgumentException();
            }
            // 先查找
            HaffManTree<T> result = searchNode(data);
            // 再删除
            return removeNode(result) ? result : null;
        }
    
        @Override
        public boolean removeNode(TreeNode<T> node) {
            if (node == null) {
                return false;
            }
            // 拿到之前的节点
            Queue<HaffManTree<T>> queue = showHaffManTree(root);
            if (queue == null || queue.isEmpty()) {
                return false;
            }
            // 删除节点
            if (!queue.remove(node)) {
                return false;
            }
            // 重新构造树
            List<HaffManTree<T>> haffManTreeList = new ArrayList<>();
            haffManTreeList.addAll(queue);
            createHaffManTree(haffManTreeList);
            return true;
        }
    
        /**
         * 查找节点
         *
         * @param data
         * @return
         */
        @Override
        public HaffManTree<T> searchNode(T data) {
            if (data == null) {
                return null;
            }
            // 队列的方式,先进先出,有数据往后面添加
            Queue<HaffManTree<T>> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()) {
                HaffManTree<T> tree = queue.poll();
                // 找到了直接返回
                if (data.equals(tree.getData()) || data == tree.getData()) {
                    return tree;
                }
                if (tree.getLeftChild() != null) {
                    queue.offer(tree.getLeftChild());
                }
                if (tree.getRightChild() != null) {
                    queue.offer(tree.getRightChild());
                }
            }
            return null;
        }
    
        /**
         * 创建哈弗曼树,返回根节点
         * 相同数据的会筛掉(不是相同权)
         *
         * @param haffManTreeList
         * @return 返回根节点
         */
        public HaffManTree<T> createHaffManTree(List<HaffManTree<T>> haffManTreeList) {
            if (haffManTreeList == null || haffManTreeList.size() < 1) {
                return null;
            }
            // 筛选,拿到合格的数据
            List<HaffManTree<T>> qualifiedList = filterNode(haffManTreeList);
            while (qualifiedList.size() > 1) {
                // 根据权值排序
                Collections.sort(qualifiedList);
                // 构造新的节点
                HaffManTree<T> left = qualifiedList.get(0);
                HaffManTree<T> right = qualifiedList.get(1);
                HaffManTree<T> parent = new HaffManTree(EMPTY_DATA, left.weight + right.weight);
                parent.setLeftChild(left);
                parent.setRightChild(right);
                qualifiedList.remove(left);
                qualifiedList.remove(right);
                qualifiedList.add(parent);
            }
            root = qualifiedList.get(qualifiedList.size() - 1);
            return qualifiedList.get(qualifiedList.size() - 1);
        }
    
        /**
         * 筛选不符合条件的节点
         *
         * @param haffManTreeList
         * @return
         */
        private List<HaffManTree<T>> filterNode(List<HaffManTree<T>> haffManTreeList) {
            if (haffManTreeList == null || haffManTreeList.isEmpty()) {
                return null;
            }
            // 把data相同的筛掉
            List<T> datas = new ArrayList<>();
            Iterator<HaffManTree<T>> it = haffManTreeList.iterator();
            while (it.hasNext()) {
                HaffManTree<T> h = it.next();
                // 之前已经有的和内容是空数据的筛掉
                if (datas.contains(h.getData()) || EMPTY_DATA.equals(h.getData())) {
                    it.remove();
                } else {
                    datas.add(h.getData());
                }
            }
            return haffManTreeList;
        }
    
        /**
         * 二叉树的层级遍历,拿到一个层级遍历好的队列,直接顺序遍历即可
         *
         * @param rootNode
         * @return
         */
        public Queue<HaffManTree<T>> showHaffManTree(HaffManTree<T> rootNode) {
            if (rootNode == null) {
                return null;
            }
            // 采用队列的方式保存节点
            Queue<HaffManTree<T>> queue = new LinkedList<>();
            Queue<HaffManTree<T>> result = new LinkedList<>();
            queue.offer(rootNode);
            while (!queue.isEmpty()) {
                HaffManTree<T> tree = queue.poll();
                result.offer(tree);
                if (tree.getLeftChild() != null) {
                    queue.offer(tree.getLeftChild());
                }
                if (tree.getRightChild() != null) {
                    queue.offer(tree.getRightChild());
                }
            }
            return result;
        }
    
        /**
         * 获取哈夫曼编码
         * 坐节点都为0,右节点都为1
         *
         * @param haffManTree
         * @return
         */
        public String getHaffManCode(HaffManTree<T> haffManTree) {
            if (haffManTree == null || haffManTree.getParent() == null) {
                return null;
            }
            Stack<Integer> resultStack = new Stack<>();
            while (haffManTree != null && haffManTree.getParent() != null) {
                HaffManTree<T> parent = haffManTree.getParent();
                // 如果当前是左子节点就为0
                if (parent.getLeftChild() != null && parent.getLeftChild() == haffManTree) {
                    resultStack.add(0);
                }
                // 如果当前是右子节点就为1
                else if (parent.getRightChild() != null && parent.getRightChild() == haffManTree) {
                    resultStack.add(1);
                }
                haffManTree = parent;
            }
            if (!resultStack.isEmpty()) {
                StringBuffer sb = new StringBuffer("");
                while (!resultStack.isEmpty()) {
                    sb.append(resultStack.pop() + "");
                }
                return sb.toString();
            }
            return null;
        }
    
        @Override
        public int compareTo(HaffManTree<T> o) {
            if (this.weight > o.weight) {
                return 1;
            } else if (this.weight < o.weight) {
                return -1;
            }
            return 0;
        }
    
        @Override
        public HaffManTree<T> getLeftChild() {
            return (HaffManTree<T>) leftChild;
        }
    
        public void setLeftChild(HaffManTree<T> leftChild) {
            this.leftChild = leftChild;
            if (leftChild != null) {
                leftChild.setParent(this);
            }
        }
    
        @Override
        public HaffManTree<T> getRightChild() {
            return (HaffManTree<T>) rightChild;
        }
    
        public void setRightChild(HaffManTree<T> rightChild) {
            this.rightChild = rightChild;
            if (rightChild != null) {
                rightChild.setParent(this);
            }
        }
    
        @Override
        public HaffManTree<T> getParent() {
            return (HaffManTree<T>) parent;
        }
    
        public void setParent(HaffManTree<T> parent) {
            this.parent = parent;
        }
    
        public HaffManTree<T> getRoot() {
            return root;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }
    
    原文作者:哈夫曼树
    原文地址: https://blog.csdn.net/pf_1308108803/article/details/78926251
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞