哈夫曼树(HuffmanTree)

一、哈夫曼树简介

1、构建哈夫曼树

       计算每个字符出现的概率,将这个概率做为权值之比。

       利用这些带权值的字符构建出哈夫曼树。

       具体构建步骤:

              ① 首先以每个带权重的字符作为根结点,组成森林,每个结点上存储相应的权值。

              ② 在森林中选取权值最小的两个树作为一棵新树的左右子树,新树的权值等于左右子树权值之和。

              ③ 从森林中剔除之前的两棵树,并将新的树加入到森林中。

              ④ 一直重复2、3步骤,直到森林中只剩下一棵树就是哈夫曼树



2、哈夫曼编码

       哈夫曼编码是现代压缩算法的基础。

       如果要传输字符串ABC直接用ASCII码着实有点冗长。而且出于对方要能解码,可用下图方式编码:
Alt
       这样其实也有点浪费。哈夫曼编码本质就是利用将出现频率最小的字符编码为最长的二进制数,而出现频率较高的字符就编码为较短的二进制数,这样又节约了很多空间。

       哈夫曼编码其实就是在哈夫曼树的基础上,规定left为0,right为0。最后对应元素的哈夫曼编码就是从根结点出发到相应叶子结点的数字组合



3、哈夫曼树总结

       n个带权重的字符构建出来的哈夫曼树有n个叶子结点。换言之,之前的n个字符最后在哈夫曼树的位置都是叶子结点。因此注定每个字符的哈夫曼编码都不可能是其他字符编码的前缀。

       哈夫曼树是带权路径长度最短的树,





二、哈夫曼树实现

1、分析

       哈夫曼树的实现需要从森林中取出权值最小的两棵树,那这个完全可以用优先队列实现或者最小堆也是一样。jdk源码的优先队列底层突然发现用的是最小堆,比较的时候需要注意!


2、实现

	public class HuffmanTree<E> {
	    private int size = 0;
	    private Node<E> root;
	    private PriorityQueue<Node<E>> forest;
	    private E nodeName;
	
	    /**
	     * 给生成的结点命名
	     *
	     * @param nodeName 多余结点的名字
	     */
	    public HuffmanTree(E nodeName) {
	        this.nodeName = nodeName;
	    }
	
	    public HuffmanTree() {
	        this(null);
	    }
	
	    private static class Node<E> implements Comparable {
	        int weight;
	        E element;
	        Node<E> parent;
	        Node<E> left;
	        Node<E> right;
	
	        public Node(int weight, E element, Node<E> parent) {
	            this.weight = weight;
	            this.element = element;
	            this.parent = parent;
	        }
	
	        @Override
	        public int compareTo(Object o) {
	            return this.weight - ((Node<E>) o).weight;
	        }
	    }
	
	    /**
	     * 根据传入的HashMap生成森林
	     */
	    public void generateForest(HashMap<E, Integer> map) {
	        forest = new PriorityQueue<>();
	        Set<E> sets = map.keySet();
	        for (E e : sets) {
	            forest.offer(new Node<>(map.get(e), e, null));
	        }
	    }
	
	    public void doHuffmanTree() {
	        if (root == null)
	            root = new Node<E>(0, null, null);
	        this.size = (forest.size() << 1) - 1;
	        while (forest.size() != 1) {
	            Node<E> left = forest.remove();
	            Node<E> right = forest.remove();
	            if (left == null || right == null)
	                return;
	            Node<E> newNode = new Node<>(left.weight + right.weight, nodeName, null);
	            newNode.left = left;
	            newNode.right = right;
	            root = newNode;
	            forest.offer(newNode);
	        }
	    }
	
	    /**
	     * 哈夫曼树中序遍历
	     */
	    public void traversal() {
	        inOrderTraversal(root);
	    }
	
	    private void inOrderTraversal(Node<E> node) {
	        if (node == null)
	            return;
	        inOrderTraversal(node.left);
	        System.out.print(node.element + " ");
	        inOrderTraversal(node.right);
	    }
	
	    public static void main(String[] args) {
	        HashMap<String, Integer> map = new HashMap<>();
	
	        map.put("B", 3);
	        map.put("C", 8);
	        map.put("D", 6);
	        map.put("A", 1);
	        map.put("E", 2);
	        HuffmanTree<String> huffmanTree = new HuffmanTree<>("tempNode");
	        huffmanTree.generateForest(map);
	        huffmanTree.doHuffmanTree();
	        System.out.println(huffmanTree.size);
	        huffmanTree.traversal();
	    }
	}
发布了54 篇原创文章 · 获赞 5 · 访问量 4603

猜你喜欢

转载自blog.csdn.net/cj1561435010/article/details/104678364