霍夫曼树

1.基本概念

  • 霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。
  • 树的带权路径长度:设一棵二叉树有 n 个叶子结点,每个叶子结点拥有一个权值W 1 ,W 2 , ...... W n ,从根结点到每个叶子结点的路径长度分别为 L1 , L2......Ln ,那么树的带权路径长度为从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln)。可以证明霍夫曼树的WPL是最小的。

 Huffman

2.构造霍夫曼树的方法

对于已知的一组叶子的权值W 1 ,W 2...... ,W n

①首先把 n 个叶子结点看做 n 棵树(仅有一个结点的二叉树),把它们看做一个森林。

②在森林中把权值最小和次小的两棵树合并成一棵树,该树根结点的权值是两棵子树权值之和。这时森林中还有 n-1 棵树。

③重复第②步直到森林中只有一棵为止。此树就是哈夫曼树。

 

n个叶子结点的哈夫曼树共有2n-1个结点。

 

3.霍夫曼编码

霍夫曼编码(Huffman Coding)是一种编码方式,是一种用于无损数据压缩的熵编码(权编码)算法。1952年,David A. Huffman在麻省理工攻读博士时所发明的,并发表于《一种构建极小多余编码的方法》(A Method for the Construction of Minimum-Redundancy Codes)一文。

 

在通信及数据传输中多采用二进制编码。为了使电文尽可能的缩短,可以对电文中每个字符出现的次数进行统计。设法让出现次数多的字符的二进制码短些,而让那些很少出现的字符的二进制码长一些。假设有一段电文,其中A,B,C,D出现的频率为0.4, 0.3, 0.2, 0.1。则得到的哈夫曼树和二进制前缀编码如图所示。在树中令所有左分支取编码为 0 ,令所有右分支取编码为1。将从根结点起到某个叶子结点路径上的各左、右分支的编码顺序排列,就得这个叶子结点所代表的字符的二进制编码。

 

这些编码拼成的电文不会混淆,因为每个字符的编码均不是其他编码的前缀,这种编码称做前缀编码

4.霍夫曼编码实现

 下面是java实现的霍弗曼编码,包括霍夫曼树的构造,编码和解码。

Java代码 复制代码  收藏代码
  1. package com.iteye.cake513.code;   
  2.   
  3. import java.util.*;   
  4. /**   
  5.  * @ClassName: Huffman   
  6.  * @Description: TODO(Huffman编码)   
  7.  * @author liujie  
  8.  * @date 2011-10-4 下午09:49:29   
  9.  *    
  10.  */  
  11.   
  12. class HuffmanNode implements Comparable<HuffmanNode> {   
  13.        
  14.     private char letter;   
  15.     private int count;//字符letter出现的频率,即权重   
  16.     private HuffmanNode left;   
  17.     private HuffmanNode right;   
  18.        
  19.     public HuffmanNode(char letter, int count) {   
  20.         this.letter = letter;   
  21.         this.left = null;   
  22.         this.right = null;   
  23.         this.count = count;   
  24.     }   
  25.        
  26.     public HuffmanNode(HuffmanNode left, HuffmanNode right) {   
  27.         this.letter = '?';   
  28.         this.left = left;   
  29.         this.right = right;   
  30.         this.count = left.count + right.count;   
  31.     }   
  32.        
  33.     //为了进行排序   
  34.     public int compareTo(HuffmanNode o) {   
  35.         return count - o.count;   
  36.     }   
  37.        
  38.     public boolean isLeaf() {   
  39.         return(this.left == null && this.right == null);   
  40.     }   
  41.   
  42.     public HuffmanNode getLeft() {   
  43.         return left;   
  44.     }   
  45.   
  46.     public HuffmanNode getRight() {   
  47.         return right;   
  48.     }   
  49.   
  50.     public char getLetter() {   
  51.         return letter;   
  52.     }   
  53.   
  54. }   
  55.   
  56. public class Huffman {   
  57.        
  58.     private HuffmanNode root;   
  59.     private HashMap<Character, String> map;//用于存放字符到编码的映射   
  60.        
  61.     @SuppressWarnings("unchecked")   
  62.     public Huffman() {   
  63.         char[] letters = "bekprs_&".toCharArray();   
  64.         int[] counts = {2,7,1,1,1,2,2,1};   
  65.         map = new HashMap<Character, String>();   
  66.         root = generateTree(letters, counts);   
  67.            
  68.         generateCodes(root, "");   
  69.         for (int i = 0; i < letters.length; i++) {   
  70.             System.out.print(letters[i] + "(" + counts[i] +") ");   
  71.         }   
  72.         System.out.println("生成二进制编码如下:");   
  73.         Iterator itr = map.entrySet().iterator();   
  74.         while (itr.hasNext()) {   
  75.             Map.Entry entry = (Map.Entry)itr.next();   
  76.             System.out.print(entry.getKey() + ":" + entry.getValue() +" ");   
  77.         }   
  78.         System.out.println();   
  79.     }   
  80.        
  81.     //构造霍夫曼树   
  82.     private HuffmanNode generateTree(char[] letters, int[] counts) {   
  83.         List<HuffmanNode> list = new LinkedList<HuffmanNode>();   
  84.            
  85.         for(int i = 0; i < letters.length; i++) {   
  86.             list.add(new HuffmanNode(letters[i], counts[i]));   
  87.         }   
  88.         while (true) {   
  89.             Collections.sort(list);   
  90.             HuffmanNode a = list.remove(0);   
  91.             if (list.isEmpty()) {   
  92.                 return a;   
  93.             }   
  94.             HuffmanNode b = list.remove(0);   
  95.             list.add(new HuffmanNode(a, b));   
  96.         }   
  97.     }   
  98.        
  99.     //生成编码,存放在HashMap中,key对应letter,value对应letter的二进制编码   
  100.     private void generateCodes(HuffmanNode root, String code) {   
  101.         if (root.isLeaf()) {   
  102.             map.put(root.getLetter(), code);   
  103.         } else {   
  104.             generateCodes(root.getLeft(), code + "0");   
  105.             generateCodes(root.getRight(), code + "1");   
  106.         }   
  107.     }   
  108.        
  109.     //对给定电文进行编码,messag中的字符必须属于生成编码用到的字符集合letters   
  110.     private String encode(String message) {   
  111.         StringBuilder result = new StringBuilder();   
  112.            
  113.         for (char c : message.toCharArray()) {   
  114.             result.append(map.get(c) + " ");   
  115.         }   
  116.         return result.toString();   
  117.     }   
  118.        
  119.     //对编码进行解码   
  120.     public String decode(String encodeMessage) {   
  121.         StringBuilder result = new StringBuilder();   
  122.         HuffmanNode node = root;   
  123.            
  124.         for (char c : encodeMessage.toCharArray()) {   
  125.             if (c == '0') {   
  126.                 node = node.getLeft();   
  127.             } else if (c == '1') {   
  128.                 node = node.getRight();   
  129.             }   
  130.             if (node.isLeaf()) {   
  131.                 result.append(node.getLetter());   
  132.                 node = root;   
  133.             }   
  134.         }   
  135.         return result.toString();   
  136.     }   
  137.        
  138.     public static void main(String[] args) {   
  139.         Huffman hfm = new Huffman();   
  140.            
  141.         String encode = hfm.encode("beekeepers_&_bees");   
  142.         System.out.println("对beekeepers_&_bees编码:" + encode);   
  143.         String decode = hfm.decode(encode);   
  144.         System.out.println("对上面进行解码:" + decode);   
  145.     }   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值