一、哈夫曼樹的概念和定義
什么是哈夫曼樹?讓我們先舉一個例子。
判定樹:在很多問題的處理過程中,需要進行大量的條件判斷,這些判斷結構的設計直接影響着程序的執行效率。例如,編制一個程序,將百分制轉換成五個等級輸出。大家可能認為這個程序很簡單,並且很快就可以用下列形式編寫出來:
if(score<60) cout<<"Bad"<<endl; else if(score<70) cout<<"Pass"<<endl else if(score<80) cout<<"General"<<endl; else if(score<90) cout<<"Good"<<endl; else cout<<"Very good!"<<endl;
定義哈夫曼樹之前先說明幾個與哈夫曼樹有關的概念:
路徑: 樹中一個結點到另一個結點之間的分支構成這兩個結點之間的路徑。
路徑長度:路徑上的分枝數目稱作路徑長度。
樹的路徑長度:從樹根到每一個結點的路徑長度之和。
結點的帶權路徑長度:在一棵樹中,如果其結點上附帶有一個權值,通常把該結點的路徑長度與該結點上的權值之積稱為該結點的帶權路徑長度(weighted path length)
什么是權值?( From 百度百科 )
計算機領域中(數據結構)權值就是定義的路徑上面的值。可以這樣理解為節點間的距離。通常指字符對應的二進制編碼出現的概率。至於霍夫曼樹中的權值可以理解為:權值大表明出現概率大!一個結點的權值實際上就是這個結點子樹在整個樹中所占的比例.abcd四個葉子結點的權值為7,5,2,4. 這個7,5,2,4是根據實際情況得到的,比如說從一段文本中統計出abcd四個字母出現的次數分別為7,5,2,4. 說a結點的權值為7,意思是說a結點在系統中占有7這個份量.實際上也可以化為百分比來表示,但反而麻煩,實際上是一樣的.
樹的帶權路徑長度:如果樹中每個葉子上都帶有一個權值,則把樹中所有葉子的帶權路徑長度之和稱為樹的帶權路徑長度。
設某二叉樹有n個帶權值的葉子結點,則該二叉樹的帶權路徑長度記為:

公式中,Wk為第k個葉子結點的權值;Lk為該結點的路徑長度。
示例:

二、哈夫曼樹的構造
注意:如果有幾棵樹根節點權值相等,並且存在一棵樹只有一個節點,應該講這課節點較小的樹先出隊列。
三、哈夫曼樹的在編碼中的應用
import java.util.PriorityQueue; public class HuffMan { private static int[] count = { 5, 24, 7, 17, 34, 5, 13 }; private static int N = count.length; private static char[] chars = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; private static PriorityQueue<Node> priorityQueue = new PriorityQueue<Node>(); private static class Node implements Comparable { Character c = null; double w; Node left; Node right; @Override public int compareTo(Object o) { Node n = (Node) o; if (this.w - n.w > 0) return 1; else if (this.w - n.w < 0) { return -1; } else { //如果兩個Node的權值相等,將是由其他節點合並而來的節點設置為較小值,先出隊列構建霍夫曼樹 if (n.c == null) { return 1; } else if (this.c == null) { return -1; } else { return 0; } } } public Node(char c, double w, Node left, Node right) { super(); this.c = c; this.w = w; this.left = left; this.right = right; } public Node(double w, Node left, Node right) { super(); this.w = w; this.left = left; this.right = right; } @Override public String toString() { return "Node [c=" + c + ", w=" + w + "]"; } } public static Node create() { for (int i = 0; i < N; i++) { priorityQueue.add(new Node(chars[i], count[i], null, null)); } while (priorityQueue.size() > 1) { Node left = priorityQueue.poll(); Node right = priorityQueue.poll(); Node newNode = new Node(left.w + right.w, left, right); priorityQueue.add(newNode); } return priorityQueue.poll(); } public static void print(Node node, StringBuilder builder) { if (node.left == null && node.right == null) { System.out.println(node.c + ":" + builder); } else { print(node.left, builder.append('0')); builder.deleteCharAt(builder.length() - 1); print(node.right, builder.append('1')); builder.deleteCharAt(builder.length() - 1); } } public static void main(String[] args) { Node root = create(); print(root, new StringBuilder()); } }
