数据结构与算法目录(http://www.javashuo.com/article/p-qvigrlkr-da.html)html
赫夫曼树又称为最优二叉树,赫夫曼树的一个最主要的应用就是赫夫曼编码。java
can you can a can as a can canner can a can.
99 97 110 32 121 111 117 32 99 97 110 32 97 32 99 97 110 32 97 115 32 97 32 99 97 110 32 99 97 110 110 101 114 32 99 97 110 32 97 32 99 97 110 46 1100011 1100001 1101110 100000 1111001 1101111 1110101 100000 1100011 1100001 1101110 100000 1100001 100000 1100011 1100001 1101110 100000 1100001 1110011 100000 1100001 100000 1100011 1100001 1101110 100000 1100011 1100001 1101110 1101110 1100101 1110010 100000 1100011 1100001 1101110 100000 1100001 100000 1100011 1100001 1101110
定长编码长度:8 * 44 = 352算法
定长编码虽然简单,但实际上有的字符出现的频率高有的低,能够将出现频率高的编码设置的短些,频率低的设置的长些,这样编码后的长度也会减小。数组
// 每一个字符出现的频率 r:1 s:1 u:1 e:1 y:1 .:1 o:1 c:7 n:8 :11 a:11 0=a,1= ,10=n,11=c,100=o,101=.,110=y,111=e,1000=u,1001=s,1010=r 11 0 10 1 1010 100 1000 1 11 0 10 1 0 1 11 0 10 1 0 1001 1 0 1 11 0 10 1 11 0 10 10 111 1010 1 11 0 10 1 0 1 11 0 10 101
采用上述编码虽然减小了长度,但没法解码。如 1 究竟是 , n, c, o ... 没法肯定。数据结构
字符的编码都不能是其余字符编码的前缀,符合此要求的编码叫作前缀编码。数据结构和算法
// 每一个字符出现的频率 r:1 s:1 u:1 e:1 y:1 .:1 o:1 c:7 n:8 :11 a:11 10=a,01= ,00=n,111=c,11000=o,110011=.,110010=y,110101=e,110100=u,110111=s,110110=r 111 10 00 01 110010 11000 110100 01 111 10 00 01 10 01 111 10 00 01 10 110111 01 10 01 111 10 00 01 111 10 00 00 110101 110110 01 111 10 00 01 10 01 111 10 00 11001
给定 n 个权值做为 n 个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为赫夫曼树。编码
在一棵树中,从一个结点往下能够达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为 1,则从根结点到第 L 层结点的路径长度为 L - 1。3d
例如上图左树:100 和 80 的路径长度是 1,50 和 30 的路径长度是 2,20 和 10 的路径长度是 3。code
定义:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。htm
例如上图左树:节点 20 的路径长度是 3,它的带权路径长度 = 路径长度 * 权 = 3 * 20 = 60。
定义:树的带权路径长度规定为全部叶子结点的带权路径长度之和,记为 WPL。
例如上图右树:树的 WPL= 1 * 100 + 2 * 50 + 3* 20 + 3 * 10 = 290
例如上图左树:树的 WPL= 2 * 100 + 2 * 50 + 2 * 20 + 2 * 10 = 360
左边的树 WPL > 右边的树的 WPL。你也能够计算除上面两种示例以外的状况,但实际上右边的树就是 {10, 20, 50, 100} 对应的哈夫曼树。至此,应该堆哈夫曼树的概念有了必定的了解了,下面看看如何去构造一棵哈夫曼树。
将一个普通的数组转换为赫夫曼树。基本原理:将数组排序后取出两个最小权值的节点造成新的节点,新节点的权值为这两个节点权值之和,而后不断轮询造成新的节点。
public static TreeNode<Integer> huffman(int[] arr) { List<TreeNode<Integer>> huffmanTree = new ArrayList<>(); for (int i : arr) { huffmanTree.add(new TreeNode(i)); } while (huffmanTree.size() > 1) { // 1. 排序 Collections.sort(huffmanTree, (TreeNode<Integer> o1, TreeNode<Integer> o2) -> { return o1.getValue() - o2.getValue(); }); // 2. 取出最小的 2 个数造成一个新的节点 TreeNode<Integer> left = huffmanTree.remove(0); TreeNode<Integer> right = huffmanTree.remove(0); TreeNode<Integer> head = new TreeNode(left.getValue() + right.getValue()); head.setLeft(left); head.setRight(right); huffmanTree.add(head); } return huffmanTree.get(0); }
天天用心记录一点点。内容也许不重要,但习惯很重要!