哈夫曼演算法java
河邊茂盛的草地,在乾草收割之前,
在獰笑著
清晨四點鍾,夏天,
尋找虔敬的儀式,
從大海藍色的中睡中,廢墟提起
清目醒神常洗頭哈哈
本篇將介紹 哈夫曼壓縮演算法(Huffman compression)
眾所周知,計算機存儲數據時,實際上存儲的是一堆0和1(二進制)。
如果我們存儲一段字元:ABRACADABRA!
那麼計算機會把它們逐一翻譯成二進制,如A:01000001;B: 01000010; !: 00001010.
每個字元佔8個bits, 這一整段字元則至少佔12*8=96 bits。
但如果我們用一些特殊的值來代表這些字元,如:
圖中,0代表A; 1111代表B;等等。此時,存儲這段字元只需30bits,比96bits小多了,達到了壓縮的目的。
我們需要這么一個表格來把原數據翻譯成特別的、占空間較少的數據。同時,我們也可以用這個表格,把特別的數據還原成原數據。
首先,為了避免翻譯歧義,這個表格需滿足一個條件: 任何一個字元用的值都不能是其它字元的前綴 。
我們舉個反例:A: 0; B: 01;這里,A的值是B的值的前綴。如果壓縮後的數據為01xxxxxx,x為0或者1,那麼這個數據應該翻譯成A1xxxxxx, 還是Bxxxxxxx?這樣就會造成歧義。
然後,不同的表格會有不同的壓縮效果,如:
這個表格的壓縮效果更好。
那麼我們如何找到 最好的表格 呢?這個我們稍後再講。
為了方便閱讀,這個表格是可以寫成一棵樹的:
這棵樹的節點左邊是0,右邊是1。任何含有字元的節點都沒有非空子節點。(即上文提及的前綴問題。)
這棵樹是在壓縮的過程中建成的,這個表格是在樹形成後建成的。用這個表格,我們可以很簡單地把一段字元變成壓縮後的數據,如:
原數據:ABRACADABRA!
表格如上圖。
令壓縮後的數據為S;
第一個字元是A,根據表格,A:11,故S=11;
第二個字元是B,根據表格,B:00,故S=1100;
第三個字元是R,根據表格,R:011,故S=1100011;
如此類推,讀完所有字元為止。
壓縮搞定了,那解壓呢?很簡單,跟著這棵樹讀就行了:
壓縮後的數據S=11000111101011100110001111101
記住,讀到1時,往右走,讀到0時,往左走。
令解壓後的字元串為D;
從根節點出發,第一個數是1,往右走:
第二個數是1,往右走:
讀到有字元的節點,返回此字元,加到字元串D里。D:A;
返回根節點,繼續讀。
第三個數是0,往左走:
第四個數是0,往左走:
讀到有字元的節點,返回此字元,加到字元串D里。D:AB;
返回根節點,繼續讀。
第五個數是0,往左走:
第六個數是1,往右走:
第七個數是1,往右走:
讀到有字元的節點,返回此字元,加到字元串D里。D:ABR;
返回根節點,繼續讀。
如此類推,直到讀完所有壓縮後的數據S為止。
壓縮與解壓都搞定了之後 我們需要先把原數據讀一遍,並把每個字元出現的次數記錄下來。如:
ABRACADABRA!中,A出現了5次;B出現了2次;C出現了1次;D出現了1次;R出現了2次;!出現了1次。
理論上,出現頻率越高的字元,我們給它一個佔用空間越小的值,這樣,我們就可以有最佳的壓縮率
由於哈夫曼壓縮演算法這塊涉及內容較多 ,文章篇幅很長;全文全方面講解了Compose布局的各方面知識。更多Android前言技術進階,我自薦一套《 完整的Android的資料,以及一些視頻課講解 》 現在私信發送「進階」或者「筆記」即可免費獲取
最後我想說:
對於程序員來說,要學習的知識內容、技術有太多太多,要想不被環境淘汰就只有不斷提升自己,從來都是我們去適應環境,而不是環境來適應我們
技術是無止境的,你需要對自己提交的每一行代碼、使用的每一個工具負責,不斷挖掘其底層原理,才能使自己的技術升華到更高的層面
Android 架構師之路還很漫長,與君共勉
C. 哈夫曼樹編碼的應用(Java語言)
1)編寫函數實現選擇parent為0且權值最小的兩個根結點的演算法
2)編寫函數實現統計字元串中字元的種類以及各類字元的個數。
3)編寫函數構造赫夫曼樹。
4)編寫函數實現由赫夫曼樹求赫夫曼編碼表。
5)編寫函數實現將正文轉換為相應的編碼文件。
6)編寫函數實現將編碼文件進行解碼。
7)編寫主控函數,完成本實驗的功能。
D. JAVA 哈夫曼樹權值求和(代碼找錯)
兄弟,你把如下第28行的count++;注釋掉,一切問題都可以解決!
自己先琢磨為什麼,不懂的再問!
importjava.util.Arrays;
importjava.util.Scanner;
publicclassa2{
publicstaticintn,count=0;
publicstaticinthe[]=newint[n+1];//預定義權值數組
publicstaticvoidHuffman(int[]a){
Arrays.sort(a);//排序
//System.out.println(a.length);
if(a.length==1)//如果長度是1結束遞歸
{
he[count++]=a[0];
return;
}
if(a.length==2)//如果長度是2結束遞歸
{
he[count++]=a[0]+a[1];
return;
}
else//長度大於2
{
intb[]=newint[a.length-1];//定義一個新數組,用於保存a
he[count++]=a[0]+a[1];
b[0]=he[--count];//新數組的第一個元素為當前數組的最小的兩個數之和
for(inti=1;i<b.length;i++)
{
b[i]=a[i+1];//賦值除第一個元素之外的值
}
//count++;
Huffman(b);//遞歸
}
}
publicstaticvoidmain(String[]args){
Scannersc=newScanner(System.in);
n=Integer.parseInt(sc.nextLine());
Strings[]=sc.nextLine().trim().split("");//輸入n個數
intd[]=newint[n];
for(inti=0;i<n;i++)
d[i]=Integer.parseInt(s[i]);//將String轉化為int的數組
Huffman(d);//遞歸調用
intsum=0;
for(inti=0;i<he.length;i++)
sum+=he[i];//求和
System.out.println(sum);
}
}