設某信源產生有五種符號u1、u2、u3、u4和u5,對應概率p1=0.4,p2=0.1,p3=p4=0.2,p5=0.1。首先,將符號按照概率由大到小排隊,如圖所示。編碼時,從最小概率的兩個符號開始,可選其中乙個支路為0,另一支路為1。這裡,我們選上支路為0,下支路為1。再將已編碼的兩支路的概率合併,並重新排隊。多次重複使用上述方法直至合併概率歸一時為止。從圖(a)和(b)可以看出,兩者雖平均碼長相等,但同一符號可以有不同的碼長,即編碼方法並不唯一,其原因是兩支路概率合併後重新排隊時,可能出現幾個支路概率相等,造成排隊方法不唯一。一般,若將新合併後的支路排到等概率的最上支路,將有利於縮短碼長方差,且編出的碼更接近於等長碼。這裡圖(a)的編碼比(b)好。
圖1 赫夫曼編碼原理
赫夫曼碼的碼字(各符號的**)是異前置碼字,即任一碼字不會是另一碼字的前面部分,這使各碼字可以連在一起傳送,中間不需另加隔離符號,只要傳送時不出錯,收端仍可分離各個碼字,不致混淆。
實際應用中,除採用定時清洗以消除誤差擴散和採用緩衝儲存以解決速率匹配以外,主要問題是解決小符號集合的統計匹配,例如黑(1)、白(0)傳真信源的統計匹配,採用0和1不同長度遊程組成擴大的符號集合信源。遊程,指相同碼元的長度(如二進碼中連續的一串0或一串1的長度或個數)。按照
ccitt標準,需要統計2×1728種遊程(長度),這樣,實現時的儲存量太大。事實上長遊程的概率很小,故ccitt還規定:若l表示遊程長度,則l=64q+r。其中q稱主碼,r為基碼。編碼時,不小於64的遊程長度由主碼和基碼組成。而當l為64的整數倍時,只用主碼的**,已不存在基碼的**。
長遊程的主碼和基碼均用赫夫曼規則進行編碼,這稱為修正赫夫曼碼,其結果有表可查。該方法已廣泛應用於
檔案傳真機中。 編輯
在變字長編碼中,如果碼字長度嚴格按照對應符號出現的概率大小逆序排列,則其平 均碼字長度為最小。
現在通過乙個例項來說明上述定理的實現過程。設將信源符號按出現的概率大小順序排列為 :
u: ( a1 a2 a3 a4 a5 a6 a7 ) [1]
0.20 0.19 0.18 0.17 0.15 0.10 0.01
給概率最小的兩個符號a6與a7分別指定為「1」與「0」,然後將它們的概率相加再與原來的 a1~a5組合並重新排序成新的原為:
u′: ( a1 a2 a3 a4 a5 a6′ )
0.20 0.19 0.18 0.17 0.15 0.11
對a5與a′6分別指定「1」與「0」後,再作概率相加並重新按概率排序得
u″:(0.26 0.20 0.19 0.18 0.17)…
直到最後得 u″″:(0.61 0.39)
赫夫曼編碼的具體方法:先按出現的概率大小排隊,把兩個最小的概率相加,作為新的概率 和剩餘的概率重新排隊,再把最小的兩個概率相加,再重新排隊,直到最後變成1。每次相 加時都將「0」和「1」賦與相加的兩個概率,讀出時由該符號開始一直走到最後的「1」, 將路線上所遇到的「0」和「1」按最低位到最高位的順序排好,就是該符號的赫夫曼編碼。
例如a7從左至右,由u至u″″,其碼字為0000;
a6按路線將所遇到的「0」和「1」按最低位到最高位的順序排好,其碼字為0001…
用赫夫曼編碼所得的平均
位元率為:σ碼長×出現概率
上例為:0.2×2+0.19×2+0.18×3+0.17×3+0.15×3+0.1×4+0.01×4=2.72 bit
可以算出本例的信源熵為2.61bit,二者已經是很接近了。 編輯
哈夫曼編碼是上個世紀五十年代由哈夫曼教授研製開發的,它借助了
資料結構當中的樹型結構,在哈夫曼演算法的支援下構造出一棵最優二叉樹,我們把這類樹命名為哈夫曼樹.因此,準確地說,哈夫曼編碼是在哈夫曼樹的基礎之上構造出來的一種編碼形式,它的本身有著非常廣泛的應用.那麼,哈夫曼編碼是如何來實現資料的
壓縮和解壓縮的呢?
眾所周知,在計算機當中,資料的儲存和加工都是以
位元組作為基本單位的,乙個西文字元要通過乙個位元組來表達,而乙個漢字就要用兩個位元組,我們把這種每乙個字元都通過相同的位元組數來表達的編碼形式稱為定長編碼.以西文為例,例如我們要在計算機當中儲存這樣的一句話:i am a teacher.就需要15個位元組,也就是120個二進位制位的資料來實現.與這種定長編碼不同的是,哈夫曼編碼是一種變長編碼.它根據字元出現的概率來構造平均長度最短的編碼.換句話說如果乙個字元在一段文件當中出現的次數多,它的編碼就相應的短,如果乙個字元在一段文件當中出現的次數少,它的編碼就相應的長.當編碼中,各碼字的長度嚴格按照對應符號出現的概率大小進行逆序排列時,則編碼的平均長度是最小的.這就是哈夫曼編碼實現資料壓縮的基本原理.要想得到一段資料的哈夫曼編碼,需要用到三個步驟:第一步:掃瞄需編碼的資料,統計原資料中各字元出現的概率.第二步:利用得到的概率值建立哈夫曼樹.第三步:對哈夫曼樹進行編碼,並把編碼後得到的碼字儲存起來.
因為定長編碼已經用相同的位數這個條件保證了任乙個字元的編碼都不會成為其它編碼的字首,所以這種情況只會出現在變長編碼當中,要想避免這種情況,我們就必須用乙個條件來制約定長編碼,這個條件就是要想成為壓縮編碼,變長編碼就必須是字首編碼.什麼是
字首編碼呢?所謂的字首編碼就是任何乙個字元的編碼都不能是另乙個字元編碼的字首.
那麼哈夫曼編碼是否是字首編碼呢?觀察a、b、c、d構成的編碼樹,可以發現b之所以成為c的字首,是因為在這棵樹上,b成為了c的父結點,從在哈夫曼樹當中,原文件中的資料字元全都分布在這棵哈夫曼樹的葉子位置,從而保證了哈夫曼編碼當中的任何乙個字元的編碼都不能是另乙個字元編碼的字首.也就是說哈夫曼編碼是一種字首編碼,也就保證了解壓縮過程當中
解碼的準確性.哈夫曼編碼的解壓縮過程也相對簡單,就是將編碼嚴格按照哈夫曼樹進行翻譯就可以了,例如遇到000,就可以順著哈夫曼樹找到i,遇到101就可以順著哈夫曼樹找到空格,以此類推,我們就可以很順利的找到原來所有的字元.哈夫曼編碼是一種一致性編碼,有著非常廣泛的應用,例如在
jpeg檔案中,就應用了哈夫曼編碼來實現最後一步的壓縮;在
[2]靜態哈夫曼方法的最大缺點就是它需要對原始資料進行兩遍掃瞄:第一遍統計原始資料中各字元出現的頻率,利用得到的頻率值建立哈夫曼樹並將樹的有關資訊儲存起來,便於解壓時使用;第二遍則根據前面得到的哈夫曼樹對原始資料進行編碼,並將編碼資訊儲存起來。這樣如果用於網路通訊中,將會引起較大的延時;對於檔案壓縮這樣的應用場合,額外的磁碟訪間將會降低該演算法的資料壓縮速度。
[3]
faller等人提出了動態哈夫曼編碼方法,它對
資料編碼的依據是動態變化的哈夫曼樹,也就是說,對第t+1個字元編碼是根據
原始資料中前t個字元得到的哈夫曼樹來進行的.壓縮和解壓子程式具有相同的初始化樹,每處理完乙個字元,壓縮和解壓方使用相同的演算法修改哈夫曼樹,因而該方法不需要為解壓而儲存樹的有關資訊。壓縮和解壓乙個字元所需的時間與該字元的編碼長度成正比,因而該過程可以實時進行。
我們分兩步來進行。第一步我們把前t個字元的哈夫曼樹轉換成它的另一種形式,在該樹中只需在第二步中簡單地把由根到葉結點alol路徑上的所有結點重量加1,就可以變成前t+1個字元的哈夫曼樹。其過就是以葉結點a(it+1)為初始的當前結點,重複地將當前結點與具有同樣重量的序號最大的結點進行交換,並使得後者的父結點成為新的當前結點,直到遇到根結點為止。以圖1為例,結點2無需進行交換,因而結點4成為新的當前結點,結點4與結點5
交換,結點8就成為當前
結點,最後結點8與結點9進行交換,結點n成為當前結點,結束該迴圈。到此為止,第一步已經完成,其結果如圖2所示,容易驗證它也是前t個字元的一種哈夫曼樹形式,因為交換只是在同重量結點之間進行。第二步通過將根到葉結點a(it+1)路徑上的所有結點重量加1,該樹就變成了前t+1個字元的哈夫曼樹。如圖3所示。乙個比較完整的動態哈夫曼編碼實例如圖4所示。
[3]
哈夫曼編碼 哈夫曼樹
1.定義 哈夫曼編碼主要用於資料壓縮。哈夫曼編碼是一種可變長編碼。該編碼將出現頻率高的字元,使用短編碼 將出現頻率低的字元,使用長編碼。變長編碼的主要問題是,必須實現非字首編碼,即在乙個字符集中,任何乙個字元的編碼都不是另乙個字元編碼的字首。如 0 10就是非字首編碼,而0 01不是非字首編碼。2....
哈夫曼樹 哈夫曼編碼
定義從a結點到b結點所經過的分支序列為從a結點到b結點的路徑 定義從a結點到b結點所進過的分支個數為從a結點到b結點的路徑長度 從二叉樹的根結點到二叉樹中所有結點的路徑長度紙盒為該二叉樹的路徑長度 huffman樹 帶權值路徑長度最小的擴充二叉樹應是權值大的外界點舉例根結點最近的擴充二叉樹,該樹即為...
哈夫曼編碼 哈夫曼樹
哈夫曼樹是乙個利用權值進行優化編碼的乙個比較奇怪的樹,他的實現比較簡單,用途也比較單一。哈夫曼樹的實現,實現要求 通過哈夫曼樹可以保證在編碼過程中不會出現例如 1000和100這樣的編碼規則,否則就會編碼失敗,因為1000和100在某些情況下的編碼會一模一樣。通過哈夫曼樹可以保證權值大的值進行編碼時...