霍夫曼編碼是一種被廣泛應用而且非常有效的資料壓縮技術,根據待壓縮資料的特徵,乙個可壓縮掉20%~90%。這裡考慮的資料指的是字串序列。要理解霍夫曼編碼,先要理解霍夫曼樹,即最優二叉樹,是一類帶權路徑長度最短的樹。
路徑是指從樹中乙個結點到另乙個結點之間的通路,路徑上的分支數目稱為路徑長度。
樹的路徑長度是從樹根到每乙個葉子之間的路徑長度之和。結點的帶權路徑長度為從該結點到樹根之間的路徑長度與該結點權的乘積,樹的帶權路徑長度為樹中所有葉子結點的帶權路徑長度之和.
假設有乙個包含100 000個字元的資料檔案要壓縮儲存。各字元在該檔案中的出現頻度見表1。僅有6種不同字元出現過,字元a出現了45000次。
a b c d e f
頻度(千字) 45 13 12 16 9 5
固定**字 000 001 010 011 100 101
變長**字 0 101 100 111 1101 1100
表1 乙個字元編碼問題。大小為100 000個字元的乙個資料檔案僅包含字元a~f,每個字元出現的頻度如表中所示。如果對每個字元賦予乙個三位的編碼,則該檔案可被編碼為300000位。如果利用表中的可變長度編碼,該檔案可被編碼為224000位。
可以用很多種方式來表示這樣乙個檔案。採用固定長度編碼,則需要三位二進位制數字來表示六個字元:a=000,b=001,…,f=101。這種方法需要300 000來對整個原檔案編碼。
而可變長度編碼是對頻度高的字元賦以短編碼,而對頻度低的字元賦以較長一些的編碼。表1顯示了這種編碼,其中一位串0表示a,四位串1100表示f。這種編碼方式需要
(45*1+13*3+12*3+16*3+9*4+5*4)*1000 = 224 000 位
來表示整個檔案,即可壓縮掉約25%。這其實就是最優字元編碼(霍夫曼編碼)
字首編碼
我們這裡考慮的編碼方案中,沒有乙個編碼是另乙個編碼的字首。這樣的編碼稱為字首編碼(或許「無字首編碼「是個更好的名字,但是字首編碼是標準的書面語)。
對任何一種二進位制字元編碼來說編碼總是簡單的,這只要將檔案中表示每個字元的編碼並置起來即可。利用表1的可變長度編碼,把包含三個字元的檔案abc編成
0 . 101 . 100 = 0 101 100,其中「.「表示並置。
在字首編碼中解碼也是很方便的。因為沒有乙個碼是其他碼的字首,故被編碼檔案的開始處的編碼是確定的。我們只要識別出第乙個編碼,將它翻譯成原文本元,再對餘下的編碼檔案重複這個解碼過程即可。在我們的例子中,可將串001 011 101唯一地分析為0.0.101.1101,因此可解碼為aabe。
下面是乙個**例項,實現了霍夫曼編碼和解碼功能:
#include #include #include #include #define n 6
using namespace std;
char c = ;//字元集合
int f = ;//出現頻率
typedef struct node
node;
void insertasprioritylist(list&prioritylist, node * node);
void insertasprioritylist(list&prioritylist, node * node)//維護乙個優先順序佇列,這裡引數一定要用引用形式
void huffmanencode( node * root);
void huffmanencode( node * leaf)//實現霍夫曼編碼
cout <&code , node *root);
void huffmandecode(vector&code , node *root)//霍夫曼解碼
if (temp->left == null && temp->right == null)
chs.push_back(temp->ch);
else
else
}int main(int argc, char **argv)
//進行霍夫曼編碼
while (huffmanlist.size() > 1)
while (!leaf.empty())
cout << endl;
vectorcodes;
codes.push_back(0);//a
codes.push_back(1);//b
codes.push_back(0);
codes.push_back(1);
codes.push_back(1);//c
codes.push_back(0);
codes.push_back(0);
codes.push_back(1);//d
codes.push_back(1);
codes.push_back(1);
codes.push_back(1);//e
codes.push_back(1);
codes.push_back(0);
codes.push_back(1);
codes.push_back(1);//f
codes.push_back(1);
codes.push_back(0);
codes.push_back(0);
huffmandecode(codes, huffmanlist.front());
cleartree(huffmanlist.front());
return 0;
}
程式的執行結果如下:
f的編碼是:1100
e的編碼是:1101
c的編碼是:100
b的編碼是:101
d的編碼是:111
a的編碼是:0
010110011111011100的解碼結果是:
a b c d e f
霍夫曼編碼(貪心演算法)
採用貪心演算法來實現霍夫曼編碼。首先輸入帯權值節點個數構造霍夫曼樹,再利用貪心演算法對節點進行編碼,在對哈夫曼樹編碼的過程中,先對權值較大的節點進行編碼,在編碼的過程中它們的字首中不能與其他已經編碼過的節點相同,這樣是為了在解碼的過程中更加容易 霍夫曼編碼的具體過程為採取可變長編碼方式,對檔案中出現...
編譯碼 霍夫曼編譯碼
1.檔案源 原始影象分塊為 8 8 在rle編碼之後做霍夫曼編碼。其中rle碼字格式如下。struct rlecode 2.構建霍夫曼表 本文中使用的為jpeg標準ac y霍夫曼表。構建乙個256維大小的碼表hufftable,其霍夫曼碼字結構如下。struct huffcode 3.關鍵幀霍夫曼編...
MATLAB實現貪心演算法
在這裡是為了實現 用貪心演算法模擬出隨機產生的20個點間的最短路徑。蟻群演算法實現,有興趣可以對比一下 matlab實現蟻群演算法 n 20 用於記錄點數 x zeros 1,n 產生乙個與經過點數相同的行向量 y zeros 1,n best 1 1 n 生成乙個用來儲存點順序的矩陣 handle...