哈夫曼編碼及文本文件的壓縮解壓(c++SourceCode)

 

	哈夫曼編碼是一種編碼方式,是可變字長編碼(VLC)的一種。以哈夫曼樹—即最優二叉樹,帶權路徑長度最小的二叉樹,經常應用於數據
壓縮。 在計算機信息處理中,“哈夫曼編碼”是一種一致性編碼法(又稱"熵編碼法"),用於數據的無損耗壓縮。這一術語是指使用一張特殊的
編碼表將源字符(例如某文件中的一個符號)進行編碼。這張編碼表的特殊之處在於,它是根據每一個源字符出現的估算概率而建立起來的(出
現概率高的字符使用較短的編碼,反之出現概率低的則使用較長的編碼,這便使編碼之後的字符串的平均期望長度降低,從而達到無損壓縮數
據的目的)。這種方法是由David.A.Huffman發展起來的。 例如,在英文中,e的出現概率很高,而z的出現概率則最低。當利用哈夫曼編碼
對一篇英文進行壓縮時,e極有可能用一個位(bit)來表示,而z則可能花去25個位(不是26)。用普通的表示方法時,每個英文字母均佔用一
個字節(byte),即8個位。二者相比,e使用了一般編碼的1/8的長度,z則使用了3倍多。倘若我們能實現對於英文中各個字母出現概率的較
準確的估算,就可以大幅度提高無損壓縮的比例。
	其中哈夫曼編碼的構造過程爲:
	(1)初始化,根據符號概率的大小按由大到小順序對符號進行排序。
	(2)把概率最小的兩個符號組成一個新符號(節點),即新符號的概率等於這兩個符號概率之和。
	(3)重複第2步,直到形成一個符號爲止(樹),其概率最後等於1。
	(4)從編碼樹的根開始回溯到原始的符號,並將每一左分枝賦值爲0,右分枝賦值爲0。
	前三步爲構造哈夫曼樹過程,既而在第四步遍歷構造出的哈夫曼樹,得到各字符的最優前綴碼.	
	爲了快速實現取集合中的最小值及向集合中插入新的元素,可以使用二叉堆來實現,二叉堆的定義及實現請另行參考.(注:由於ASCII碼及
char型數據範圍的限制,編碼過程中生成的哈夫曼樹不會非常大,所以生成哈夫曼樹所需要的時間在整個壓縮過程中顯得微不足道,可用其它方
式來生成哈夫曼樹.)
以一棵生成的哈夫曼樹爲例(圖片來自:http://blog.163.com/yuang_yu_ping/blog/static/4693287620098172049346/):
圖片中的哈夫曼樹對應的綠色即葉結點爲待編碼字符,對應的前綴碼分別爲:
A : 10
C : 01
D : 11
E : 000
M : 001
	在文本文件的壓縮過程中,首先取ASCII字符對應的出現次數,然後對 0x00~0xff 這些字符根據出現頻率生成對應的前綴碼,然後讀取
文件 ,爲每一個字符進行編碼.
	編碼問題已經解決了,可是如果要實現文件壓縮,壓縮文件的編碼如何進行存儲呢? 首先明確一點,源文件壓縮之後的編碼對應的是二進制的
位段,而C語言中每個char 類型佔用八位的空間,我們可以把編碼後的二進制位以八位爲一段,生成對應的字符來存儲.對最後不足八位的二進制段,
補足八位,用一個字符表示,依次存儲這些轉化來的字符,即可生成壓縮文件.
	另,爲了解壓的需要,我們要存儲編碼的信息至壓縮文件中,可以採用源文件中各字符出現的頻率來記錄,解碼時讀取這些信息,再利用這些信息
重新生成一棵同樣的哈夫曼樹,另外壓縮文件頭中存儲有最後一個字符實際佔用的位數,用以在解壓時對最後一個字符正確處理.
	至此,用哈夫曼編碼來實現文本文件壓縮的大致過程也算明白了,下面來談一談具體實現:
	首先是哈夫曼樹的結點,
	生成哈夫曼樹時要用到的堆
	進行壓縮工作時的變量:
	CHuffMan類的聲明:
	思考:從運行效果上來看,壓縮的比例不是非常滿意,壓縮率達不到25%,應該可以採用動態哈夫曼樹的編碼來對大文件的壓縮進行優化,
從而達到更優的壓縮率。確定一個初始哈夫曼樹,然後根據當前處理過的字符動態的調整哈夫曼樹的結構,解壓過程同樣根據解壓過的字符調整哈夫曼樹
結構。   壓縮與解壓的時間效率有待提高,本程序在壓縮及解壓過程中對硬盤進行了大量的讀寫,使速度受到影響,可以通過緩衝帶還實現提速,即構
造內存緩衝區,每次讀寫多個字符,既而進行處理。
	
	(注:根據哈夫曼樹的構成原理,可以預見一種特殊的情況:哈夫曼樹的結構爲每一層只有一個葉結點,這種情況下的每個字符對應的前綴碼
長度最高會達到256位,在此程序中未進行特殊考慮。)
	運行效果:





	
	源代碼:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章