哈夫曼树构造过程:
列表里选出权重(或者出现次数)最低的两个,构成新树的左右子节点,新树父节点的权重为这两个子节点权重之和,将父节点(树)丢进列表里,重复操作,最后列表只剩一个,即哈夫曼树,所有子树的左边标0右边标1,节点的路径即哈夫曼编码;
Demo:
package testHuffman; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; public class TestHuffman { public static void main(String[] args) { //优先级队列,自动排序 PriorityQueue<Node> q = new PriorityQueue<>(new Comparator<Node>() { @Override public int compare(Node o1, Node o2) { if(o1.priority == o2.priority) { return o1.n-o2.n; }else { return o1.priority - o2.priority; } } }); //初始数据 Map<String,Integer> map = new HashMap<>(); map.put("A",5); map.put("B",24); map.put("C",7); map.put("D",17); map.put("E",34); map.put("F",5); map.put("G",13); //初始数据放入队列 for(String v:map.keySet()) { System.out.println("放入队列:"+v+":"+map.get(v)); q.add(new Node(map.get(v), v, null, null, 1)); } System.out.println("=队列="+q); //构造哈夫曼树 while(q.size()>1) { //取出优先级最小的两个 Node n1 = q.poll(); Node n2 = q.poll(); System.out.println("取出:"+n1+n2); //构成新树 Node newNode = new Node(n1.priority+n2.priority, "("+n1.name+""+n2.name+")", n1, n2, n1.n>n2.n?n1.n+1:n2.n+1); System.out.println("放入:"+newNode); //重新放入队列 q.add(newNode); System.out.println("=队列="+q); } //取出哈夫曼树 Node tree = q.poll(); Map<String, String> code_word = getTreeCode(tree); System.out.println(code_word); Map<String, String> word_code = new HashMap<>(); for(String code:code_word.keySet()) { word_code.put(code_word.get(code), code); } //测试 String msg = "DCABCFDBFABEGA"; for(String word:word_code.keySet()) { msg = msg.replaceAll(word, word_code.get(word)); } System.out.println("编码:"+msg); String subCode = ""; String reMsg = ""; for(int i=0;i<msg.length();i++) { subCode += msg.substring(i, i+1); if(code_word.containsKey(subCode)) { reMsg += code_word.get(subCode); subCode = ""; } } System.out.println("消息:"+reMsg); } private static Map<String,String> getTreeCode(Node root) { Map<String,String> m = new HashMap<>(); getRoad("",root,m); return m; } //构造路径,左0右1 private static Map<String,String> getRoad(String r, Node n, Map<String,String> m) { if(n.left == null) { m.put(r, n.name); }else { getRoad(r+"0", n.left, m); } if(n.right == null) { m.put(r, n.name); }else { getRoad(r+"1", n.right, m); } return m; } } class Node{ public int priority; public String name; public Node left; public Node right; public int n;//用于保存树层级,优先级相同按层级排序,每次选层级最小的两个 public Node(int priority, String name, Node left, Node right, int n) { this.priority = priority; this.name = name; this.left = left; this.right = right; this.n = n; } @Override public String toString() { return "{"+priority + ":" + name+"}"; } }结果:
同组数据产生的哈夫曼树可能不唯一,存在超过两个相同权重节点的选择问题和左右子树的位置问题;