在計算機數據處理中,霍夫曼編碼使用變長編碼表對源符號(如文件中的一個字母)進行編碼,其中變長編碼表是經過一種評估來源符號出現機率的方法獲得的,出現機率高的字母使用較短的編碼,反之出現機率低的則使用較長的編碼,這便使編碼以後的字符串的平均長度、指望值下降,從而達到無損壓縮數據的目的。java
例如,在英文中,e的出現機率最高,而z的出現機率則最低。當利用霍夫曼編碼對一篇英文進行壓縮時,e極有可能用一個比特來表示,而z則可能花去25個比特(不是26)。用普通的表示方法時,每一個英文字母均佔用一個字節(byte),即8個比特。兩者相比,e使用了通常編碼的1/8的長度,z則使用了3倍多。假若咱們能實現對於英文中各個字母出現機率的較準確的估算,就能夠大幅度提升無損壓縮的比例。node
霍夫曼樹又稱最優二叉樹,是一種帶權路徑長度最短的二叉樹。所謂樹的帶權路徑長度,就是樹中全部的葉結點的權值乘上其到根結點的路徑長度(若根結點爲0層,葉結點到根結點的路徑長度爲葉結點的層數)。樹的路徑長度是從樹根到每一結點的路徑長度之和,記爲WPL=(W1L1+W2L2+W3L3+...+WnLn),N個權值Wi(i=1,2,...n)構成一棵有N個葉結點的二叉樹,相應的葉結點的路徑長度爲Li(i=1,2,...n)。能夠證實霍夫曼樹的WPL是最小的。數據結構
演算過程
進行霍夫曼編碼前,咱們先建立一個霍夫曼樹。app
⒈將每一個英文字母依照出現頻率由小排到大,最小在左。ui
⒉每一個字母都表明一個終端節點(葉節點),比較F.O.R.G.E.T五個字母中每一個字母的出現頻率,將最小的兩個字母頻率相加合成一個新的節點。如Fig.2所示,發現F與O的頻率最小,故相加2+3=5。this
⒊比較5.R.G.E.T,發現R與G的頻率最小,故相加4+4=8。編碼
⒋比較5.8.E.T,發現5與E的頻率最小,故相加5+5=10。加密
⒌比較8.10.T,發現8與T的頻率最小,故相加8+7=15。.net
⒍最後剩10.15,沒有能夠比較的對象,相加10+15=25。設計
進行編碼
1.給霍夫曼樹的全部左鏈結'0'與
霍夫曼樹
霍夫曼樹
右鏈結'1'。
2.從樹根至樹葉依序記錄全部字母的編碼
設有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x,y,z}。
給定一個包含26個英文字母的文件,統計每一個字符出現的機率,根據計算的機率構造一顆哈夫曼樹。
並完成對英文文件的編碼和解碼。
要求:
(1)準備一個包含26個英文字母的英文文件(能夠不包含標點符號等),統計各個字符的機率
(2)構造哈夫曼樹
(3)對英文文件進行編碼,輸出一個編碼後的文件
(4)對編碼文件進行解碼,輸出一個解碼後的文件
(5)撰寫博客記錄實驗的設計和實現過程,並將源代碼傳到碼雲
(6)把實驗結果截圖上傳到雲班課
滿分:6分。
酌情打分。
public class HuffmanNode { private int weight;//權值 private int parent; private int leftChild; private int rightChild; public HuffmanNode(int weight,int parent,int leftChild,int rightChild){ this.weight=weight; this.parent=parent; this.leftChild=leftChild; this.rightChild=rightChild; } void setWeight(int weight){ this.weight=weight; } void setParent(int parent){ this.parent=parent; } void setLeftChild(int leftChild){ this.leftChild=leftChild; } void setRightChild(int rightChild){ this.rightChild=rightChild; } int getWeight(){ return weight; } int getParent(){ return parent; } int getLeftChild(){ return leftChild; } int getRightChild(){ return rightChild; } }
public class HuffmanCode { private String character; private String code; HuffmanCode(String character,String code){ this.character=character; this.code=code; } HuffmanCode(String code){ this.code= code; } void setCharacter(String character){ this.character=character; } void setCode(String code){ this.code=code; } String getCharacter(){ return character; } String getCode(){ return code; } }
public class HuffmanTree { //初始化一個huffuman樹 public static void initHuffmanTree(HuffmanNode[] huffmanTree,int m){ for(int i=0;i<m;i++){ huffmanTree[i] = new HuffmanNode(0,-1,-1,-1); } } //初始化一個huffmanCode public static void initHuffmanCode(HuffmanCode[] huffmanCode,int n){ for(int i=0;i<n;i++){ huffmanCode[i]=new HuffmanCode("",""); } } //獲取huffmanCode的符號 public static void getHuffmanCode(HuffmanCode[] huffmanCode , int n,char[] chars){ for(int i=0;i<n;i++){ String temp = ""+chars[i]; huffmanCode[i] = new HuffmanCode(temp,""); } } //獲取huffman樹節點頻數 public static void getHuffmanWeight(HuffmanNode[] huffmanTree , int n,int[] ints){ for(int i=0;i<n;i++){ int temp = ints[i]; huffmanTree[i] = new HuffmanNode(temp,-1,-1,-1); } } //從n個結點中選取最小的兩個結點 public static int[] selectMin(HuffmanNode[] huffmanTree ,int n) { int min[] = new int[2]; class TempNode { int newWeight;//存儲權 int place;//存儲該結點所在的位置 TempNode(int newWeight,int place){ this.newWeight=newWeight; this.place=place; } void setNewWeight(int newWeight){ this.newWeight=newWeight; } void setPlace(int place){ this.place=place; } int getNewWeight(){ return newWeight; } int getPlace(){ return place; } } TempNode[] tempTree=new TempNode[n]; //將huffmanTree中沒有雙親的結點存儲到tempTree中 int i=0,j=0; for(i=0;i<n;i++) { if(huffmanTree[i].getParent()==-1&& huffmanTree[i].getWeight()!=0) { tempTree[j]= new TempNode(huffmanTree[i].getWeight(),i); j++; } } int m1,m2; m1=m2=0; for(i=0;i<j;i++) { if(tempTree[i].getNewWeight()<tempTree[m1].getNewWeight())//此處不讓取到相等,是由於結點中有相同權值的時候,m1取最前的 m1=i; } for(i=0;i<j;i++) { if(m1==m2) m2++;//當m1在第一個位置的時候,m2向後移一位 if(tempTree[i].getNewWeight()<=tempTree[m2].getNewWeight()&& i!=m1)//此處取到相等,是讓在結點中有相同的權值的時候, //m2取最後的那個。 m2=i; } min[0]=tempTree[m1].getPlace(); min[1]=tempTree[m2].getPlace(); return min; } //建立huffmanTree public static void createHaffmanTree(HuffmanNode[] huffmanTree,int n){ if(n<=1) System.out.println("Parameter Error!"); int m = 2*n-1; //initHuffmanTree(huffmanTree,m); for(int i=n;i<m;i++) { int[] min=selectMin(huffmanTree,i); int min1=min[0]; int min2=min[1]; huffmanTree[min1].setParent(i); huffmanTree[min2].setParent(i); huffmanTree[i].setLeftChild(min1); huffmanTree[i].setRightChild(min2); huffmanTree[i].setWeight(huffmanTree[min1].getWeight()+ huffmanTree[min2].getWeight()); } } //建立huffmanCode public static void createHaffmanCode(HuffmanNode[] huffmanTree,HuffmanCode[] huffmanCode,int n){ char[] code = new char[26]; int start; int c; int parent; int temp; code[n-1]='0'; for(int i=0;i<n;i++) { StringBuffer stringBuffer = new StringBuffer(); start=n-1; c=i; while( (parent=huffmanTree[c].getParent()) >=0 ) { start--; code[start]=((huffmanTree[parent].getLeftChild()==c)?'0':'1'); c=parent; } for(;start<n-1;start++){ stringBuffer.append(code[start]); } huffmanCode[i].setCode(stringBuffer.toString()); } }
import java.io.*; import static week15.HuffmanTree.*; public class HuffmanTest { private char[] chars = new char[]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s' ,'t','u','v','w','x','y','z'}; private int[] number = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; public String txtString(File file){ StringBuilder result = new StringBuilder(); try{ BufferedReader br = new BufferedReader(new FileReader(file));//構造一個BufferedReader類來讀取文件 String s = null; while((s = br.readLine())!=null){//使用readLine方法,一次讀一行 result.append(System.lineSeparator()+s); num(s); } br.close(); }catch(Exception e){ e.printStackTrace(); } return result.toString(); } public void num(String string){ for(int i = 0;i<26;i++){ int temp = 0; for(int j = 0;j<string.length();j++){ if(string.charAt(j) == chars[i]) temp++; } number[i] += temp; } } public int[] getNumber(){ return number; } public char[] getChars(){ return chars; } public static void main(String[] args){ File file = new File("D:\\","inputhuffman.txt"); HuffmanTest huffmanTest= new HuffmanTest(); String temp = huffmanTest.txtString(file); int[] num = huffmanTest.getNumber(); char[] chars = huffmanTest.getChars(); int n; int m; n = 26; m=2*n-1; HuffmanNode[] huffmanTree = new HuffmanNode[m]; HuffmanCode[] huffmanCode = new HuffmanCode[n]; //初始化huffmanTree,huffmanCode initHuffmanTree(huffmanTree,m); initHuffmanCode(huffmanCode,n); //獲取huffmanCode的符號 getHuffmanCode(huffmanCode,n,chars); //獲取huffmanTree的頻數 getHuffmanWeight(huffmanTree,n,num); //建立huffmanTree createHaffmanTree(huffmanTree,n); //建立huffmanCode createHaffmanCode(huffmanTree,huffmanCode,n); //輸出huffmanCode編碼 ouputHaffmanCode(huffmanCode,n); String result = ""; for(int i = 0;i<temp.length();i++){ for(int j = 0;j<huffmanCode.length;j++){ if(temp.charAt(i) == huffmanCode[j].getCharacter().charAt(0)) result +=huffmanCode[j].getCode(); } } System.out.println("加密"); System.out.println(result); System.out.println("解密"); }
問題1:只輸出了兩個數的編碼
問題1解決方案:
錯誤地將26個字符數刪成兩個 因而其餘地方輸入多少個也沒用
改正以後就沒問題了