簡單快速的哈夫曼編碼(翻譯)
本文描述在網上能夠找到的最簡單,最快速的哈夫曼編碼。本方法不使用任何擴充套件動態庫,比如
stl或者元件。只使用簡單的
c函式,比如:
memset
,memmove
,qsort
,malloc
,realloc
和memcpy。
因此,大家都會發現,理解甚至修改這個編碼都是很容易的。
背景
哈夫曼壓縮是個無損的壓縮演算法,一般用來壓縮文字和程式檔案。哈夫曼壓縮屬於可變**長度演算法一族。意思是個體符號(例如,文字檔案中的字元)用乙個特定長度的位序列替代。因此,在檔案中出現頻率高的符號,使用短的位序列,而那些很少出現的符號,則用較長的位序列。
編碼使用
我用簡單的
c函式寫這個編碼是為了讓它在任何地方使用都會比較方便。你可以將他們放到類中,或者直接使用這個函式。並且我使用了簡單的格式,僅僅輸入輸出緩衝區,而不象其它文章中那樣,輸入輸出檔案。
bool compresshuffman(byte *psrc, int nsrclen, byte *&pdes, int &ndeslen);
bool decompresshuffman(byte *psrc, int nsrclen, byte *&pdes, int &ndeslen);
要點說明
為了讓它
(huffman.cpp)
快速執行,我花了很長時間。同時,我沒有使用任何動態庫,比如
stl或者
mfc。它壓縮
1m資料少於
100ms(p3
處理器,主頻
1g)。
壓縮**非常簡單,首先用
ascii
值初始化
511個哈夫曼節點:
chuffmannode nodes[511];
for(int ncount = 0; ncount < 256; ncount++)
nodes[ncount].byascii = ncount;
然後,計算在輸入緩衝區資料中,每個
ascii
碼出現的頻率:
for(ncount = 0; ncount < nsrclen; ncount++)
nodes[psrc[ncount]].nfrequency++;
然後,根據頻率進行排序:
qsort(nodes, 256, sizeof(chuffmannode), frequencycompare);
現在,構造哈夫曼樹,獲取每個
ascii
碼對應的位序列:
int nnodecount = gethuffmantree(nodes);
構造哈夫曼樹非常簡單,將所有的節點放到乙個佇列中,用乙個節點替換兩個頻率最低的節點,新節點的頻率就是這兩個節點的頻率之和。這樣,新節點就是兩個被替換節點的父節點了。如此迴圈,直到佇列中只剩乙個節點(樹根)。
// parent node
pnode = &nodes[nparentnode++];
// pop first child
pnode->pleft = popnode(pnodes, nbacknode--, false);
// pop second child
pnode->pright = popnode(pnodes, nbacknode--, true);
// adjust parent of the two poped nodes
pnode->pleft->pparent = pnode->pright->pparent = pnode;
// adjust parent frequency
pnode->nfrequency = pnode->pleft->nfrequency + pnode->pright->nfrequency;
這裡我用了乙個好的訣竅來避免使用任何佇列元件。我先前就直到
ascii
碼只有256
個,但我分配了511個(
chuffmannode nodes[
511
]
),
前255個記錄ascii碼,而用後255個記錄哈夫曼樹中的父節點。並且在構造樹的時候只使用乙個指標陣列(chuffmannode *pnodes[256])來指向這些節點。同樣使用兩個變數來操作佇列索引(int nparentnode = nnodecount;nbacknode = nnodecount –1)。
那麼,壓縮的最後一步是將每個ascii編碼寫入輸出緩衝區中:
int ndesindex = 0, ncodelength, dwcode;
// loop to write codes
for(ncount = 0; ncount < nsrclen; ncount++)
}注意:在壓縮緩衝區中,我們必須儲存哈夫曼樹的節點以及位序列,這樣我們才能在解壓縮時重新構造哈夫曼樹(只需儲存
ascii
值和對應的位序列)。
解壓縮比構造哈夫曼樹要簡單的多,將輸入緩衝區中的每個編碼用對應的
ascii
碼逐個替換就可以了。只要記住,這裡的輸入緩衝區是乙個包含每個
ascii
值的編碼的位流。因此,為了用
ascii
值替換編碼,我們必須用位流搜尋哈夫曼樹,直到發現乙個葉節點,然後將它的
ascii
值新增到輸出緩衝區中:
int ndesindex = 0;
while(ndesindex < ndeslen)
pdes[ndesindex++] = pnode->byascii;
}原始檔:
哈夫曼編碼 哈夫曼樹
1.定義 哈夫曼編碼主要用於資料壓縮。哈夫曼編碼是一種可變長編碼。該編碼將出現頻率高的字元,使用短編碼 將出現頻率低的字元,使用長編碼。變長編碼的主要問題是,必須實現非字首編碼,即在乙個字符集中,任何乙個字元的編碼都不是另乙個字元編碼的字首。如 0 10就是非字首編碼,而0 01不是非字首編碼。2....
哈夫曼樹 哈夫曼編碼
定義從a結點到b結點所經過的分支序列為從a結點到b結點的路徑 定義從a結點到b結點所進過的分支個數為從a結點到b結點的路徑長度 從二叉樹的根結點到二叉樹中所有結點的路徑長度紙盒為該二叉樹的路徑長度 huffman樹 帶權值路徑長度最小的擴充二叉樹應是權值大的外界點舉例根結點最近的擴充二叉樹,該樹即為...
哈夫曼編碼 哈夫曼樹
哈夫曼樹是乙個利用權值進行優化編碼的乙個比較奇怪的樹,他的實現比較簡單,用途也比較單一。哈夫曼樹的實現,實現要求 通過哈夫曼樹可以保證在編碼過程中不會出現例如 1000和100這樣的編碼規則,否則就會編碼失敗,因為1000和100在某些情況下的編碼會一模一樣。通過哈夫曼樹可以保證權值大的值進行編碼時...