14.Huffman(哈夫曼)編碼
首先宣告一下,我感覺這個演算法它的程式碼有點複雜,等一下我寫的時候你就知道了。但是在理解上來說很簡單,這就是它最矛盾的地方!!
1.問題解析
由上圖可以看出每個字元在檔案中出現的次數(頻率)以及編碼方式,本題研究的就是實現最優字元編碼,要求編碼檔案所需位元數目最少。就像上圖,對於定長編碼字來說:(45+13+12+16+9+5)*3=300;對於變長編碼字來說:(45*1+13*3+12*3+16*3+9*4+5*4)=224;所以變長編碼的所需總位元數比定長編碼更優
2.編碼定義
圖中所示:每個字母旁邊的數字為其頻數,兩個父母的父節點數值由兩個子節點數值相加得到。同時一個父節點的左邊子節點編號為0,右邊子節點編號為1,如圖中所示,a編碼為:000,或0,。
3.貪婪選擇
由上圖所示,先選取字元中頻數最小的兩個組合成二叉樹,其父節點數值為兩頻數之和,然後以父節點的數值來替代原來兩個點,放入原字元頻數陣列中,再選取字元中頻數最小的兩個組合成二叉樹,直到所有的字元都在同一棵二叉樹上。然後由字元所在位置的編碼就是題目要求的最優編碼
輸入:字符集C及頻數f(C)
輸出:實現最優編碼方式時的各字元編碼
演算法虛擬碼:
HUFFMAN(C)
1. n<-|C|
2. Q<-C
3. for i<- 1 to n-1
4. do 分配新的節點z
5. left[z]<-x<-EXTRACT-MIN(Q)
6. right[z]<-y<-EXTRACT-MIN(Q)
7. f[z]<-f[x]+f[y]
8. INSERT(Q,z)
9. return EXTRACT-MIN(Q) //返回樹的根
JAVA:
Binarytree.java
package Jamin;
public class Binarytree implements Comparable<Binarytree>{ int key; char data; Binarytree left; Binarytree right; public Binarytree() {} public Binarytree(int k,char d,Binarytree l,Binarytree r) {//將輸入的值賦值到建立的結構變數中 key=k; data=d; left=l; right=r; } public String toString() {//用來做後期列印 return "Character:"+data+" frequency:"+key; } public int compareTo(Binarytree x) {// 比較 if(key>x.key) return 1; if(key<x.key) return -1; return 0; } public void inorderwalk() {//呼叫遍歷輸出 if(left!=null) left.inorderwalk(); System.out.print(toString()); if(right!=null) right.inorderwalk(); } }
Huffman.java
package Jamin; import java.util.PriorityQueue; public class Huffman { public static Binarytree huffman(int[] f,char[] d) { int i,n=f.length; PriorityQueue<Binarytree> Q=new PriorityQueue<Binarytree>(n); for(i=0;i<n;i++) { Binarytree t=new Binarytree(f[i],d[i],null,null); Q.add(t); } for(i=0;i<n-1;i++) { Binarytree x,y,z; x=Q.poll();//從優先佇列中彈出最小值 y=Q.poll(); z=new Binarytree(x.key+y.key,'*',x,y); Q.add(z); } return Q.poll(); } public static void printcode(Binarytree t,String c) { if(t.left!=null)//向左邊搜尋,變0 printcode(t.left,c+"0"); if(t.right!=null)//向右邊搜尋,變1 printcode(t.right,c+"1"); if(t.left==null&&t.right==null) System.out.println(t+" code:"+c+" "); } }
Test.java
package Jamin;
public class Test {
public static void main(String[] args) { // TODO Auto-generated method stub int f[]= {45,13,12,16,9,5},i; char d[]= {'a','b','c','d','e','f'}; Binarytree h=Huffman.huffman(f, d); Huffman.printcode(h, ""); System.out.println(); } } 輸出結果:
Character:a frequency:45 code:0 Character:c frequency:12 code:100 Character:b frequency:13 code:101 Character:f frequency:5 code:1100 Character:e frequency:9 code:1101 Character:d frequency:16 code:111