1.概述
信息時代,人們對使用計算機獲取信息、處理信息的依賴性越來越高。計算機系統面臨的是數值、文字、語言、音樂、圖形、動畫、靜圖像、電視視頻圖像等多種媒體。數字化的視頻和音頻信號的數量之大是驚人的,對於電視畫面的分辨率640×480的彩色圖像,30幀/s,則一秒鐘的數據量爲:640×480×24×30=221 12M,所以播放時,需要221Mbps的通信迴路。存儲時,1張CD可存640M,則僅可以存放 2 89s的數據。
2哈夫曼算法編碼原理與應用
大數據量的圖像信息會給存儲器的存儲容量,通信幹線信道的帶寬,以及計算機的處理速度增加極大的壓力。單純靠增加存儲器容量,提高信道帶寬以及計算機的處理速度等方法來解決這個問題是不現實的,這時就要考慮壓縮。壓縮的關鍵在於編碼,如果在對數據進行編碼時,對於常見的數據,編碼器輸出較短的碼字;而對於少見的數據則用較長的碼字表示,就能夠實現壓縮。
2 1舉個例子:假設一個文件中出現了8種符號S0,SQ,S2,S3,S4,S5,S6,S7,那麼每種符號要編碼,至少需要3bit。假設編碼成000,001, 010,011,100,101,110,111。那麼符號序列S0S1S7S0S1S6S2S2S3S4S5S0S0S1編碼後變成 000001111000001110010010011100101000000001,共用了42bit。我們發現S0,S1,S2這3個符號出現的頻率比較大,其它符號出現的頻率比較小,我們採用這樣的編碼方案:S0到S7的碼遼分別01,11,101,0000,0001,0010,0011, 100,那麼上述符號序列變成011110001110011101101000000010010010111,共用了39bit。儘管有些碼字如 S3,S4,S5,S6變長了(由3位變成4位),但使用頻繁的幾個碼字如S0,S1變短了,所以實現了壓縮。對於上述的編碼可能導致解碼出現非單值性:比如說,如果S0的碼字爲01,S2的碼字爲011,那麼當序列中出現011時,你不知道是S0的碼字後面跟了個1,還是完整的一個S2的碼字。因此,編碼必須保證較短的編碼決不能是較長編碼的前綴。符合這種要求的編碼稱之爲前綴編碼。要構造符合這樣的二進制編碼體系,可以通過二叉樹來實現。
1)首先統計出每個符合出現的頻率,上例SO到S7的出現頻率分別爲4/14,3/14,2/14,1/14,1/14,1/14,1/14,1/14。
2)從左到右把上述頻率按從小到大的順序排列。
3)每一次選出最小的兩個值,作爲二叉樹的兩個葉子節點,將和作爲它們的根節點,這兩個葉子節點不再參與比較,新的根節點參與比較。
4)重複(3),直到最後得到和爲1的根節點。
將形成的二叉樹的左節點標0,右節點標1。把從最上面的根節點到最下面的葉子節點路徑中遇到的0,1序列串起來,得到各個符號的編碼。
可以看到,符號只能出現在樹葉上,任何一個字符的路徑都不會是另一字符路徑的前綴路徑,這樣,前綴編碼也就構造成功了。
這樣一棵二叉樹在數據結構課程中稱之爲Huffman樹,常用於最佳判定,它是最優二叉樹,是一種帶權路徑長度最短的二叉樹。所謂樹的帶權路徑長度,就是樹中所有的葉結點的權值乘上其到根結點的路徑長度(若根結點爲0層,葉結點到根結點的路徑長度爲葉結點的層數)。樹的帶權路徑長度記爲:WPL= (W1*L1+W2*L2+W3*L3+…+Wn*Ln),N個權值Wi(i=1,2,…n)構成一棵有N個葉結點的二叉樹,相應的葉結點的路徑長度爲 Li(i=1,2,…n)。Huffman樹得出的WPL值最小。
2 2在對一幅大小爲100,672bytes 8位BMP圖像文件進行Huffman編碼過程中,作者按照以下步驟實現了的壓縮和解壓縮算法。
1)掃描位圖文件的全部數據(對應用於調色板的編碼),完成數據頻度的統計。
2)依據數據出現的頻度建立哈夫曼樹。
3)將哈夫曼樹的信息寫入輸出文件(壓縮後文件),以備解壓縮時使用。
4)進行第二遍掃描,將原文件所有編碼數據轉化爲哈夫曼編碼,保存到輸出文件。解壓縮則爲逆過程,以下是編碼和解碼的實現算法。
a)定義數據結構Node如下:
Struct Node
{long freq;//該節點符號的頻率值,初值爲0
int parent;//該節點父節點的序號,初值爲-1
int right;//該節點右子節點的序號,初值爲-1
int left;//該節點左子節點的序號,初值爲-1
|Bmp tree[511]
說明:
之所以有511個節點,是因爲每個字節可表示的符號個數爲256個(對應於256種顏色)二叉樹有256個葉節點,根據二叉樹的性質總節點數爲 2·256-1=511個節點。這裏用0~255個元素來依次對應256種顏色。由第256以後的元素來依次對應形成的各個父節點的信息,即父節點的編號從256開始。
b)按照前述的壓縮步驟,先對欲壓縮文件的各個符號的使用次數進行統計,填充於bmp tree[0~255] ·freq項內;在已有的節點中找出頻率最低的兩個節點,給出它們的父節點,將兩個節點號填充於父節點的right,left,將父節點號填充於兩個節點的Parent內。重複步驟直到根節點,建樹工作完成。
建樹完成後進行編碼,對每個符號從符號的父節點開始。若節點的父節點值不爲-1,則一直進行下去,直到樹根。回溯過程中遇左出0,遇右出1輸出編碼。
Huffman編碼遞歸過程如下:
Void Bmp Huff Code(int node,int child)
if{Bmp tree[node] Parent!=-1};//父節點爲-1的節點是樹根
Bmp Huff Code(Bmp tree[node] parent,node);//若不爲-1則遞歸
if(child≠-1);//若不爲葉節點
{if(child=bmp tree[node] right);//右子節點,輸出“1”
outputbit(1);
else if(child=bmp tree[node] left);//左子節點,輸出“0”