演算法學習-哈夫曼編碼(c++實現),哈夫曼
哈夫曼編碼
哈夫曼編碼雖然簡單,但是是一個非常重要的編碼方式,它解決了資料存放區的一個非常重要的問題:壓縮!它的編碼方式是最優的,無損的,尤其在映像中使用的非常多。下面講下它的原理。
編碼方式
哈夫曼編碼的構造是依據權值的大小來實現的。首先根據權值構造哈夫曼樹,然後對哈夫曼樹進行逆向遍曆,從而找到每個節點的編碼方式。
例如:
abbcccdddde這個是一個字串,一共有5個字元。每個字元的權值就是出現的頻率,那麼a就是1,b權值為2,c的權值為3,d的權值為4,e的權值為1。在普通的編碼方式中,表示5個字母最少要3位,也就是3bit.那麼這串字元就需要1*3+2*3+3*3+4*3+1*3=33 bits。而使用哈夫曼的編碼呢?
構造哈夫曼樹的流程是每次找到權值最小的兩個,放到一起,組成一顆樹,根節點是權值的和。
第一步:
2 / \ 1 1
這樣權值為1的a和e就已經構造完了。並且把當前的2放回權值列表,下面最小的兩個是這個2和b的權值2。
4 / \ 2 2 / \ 1 1
這樣第二步就構造完了,再把4放回權值列表,繼續找,依次類推
...省略ing
結果的哈夫曼樹:
11 / \ 7 4 / \ / \ 3 4 2 2 / \ 1 1
好,這就是最終的哈夫曼樹。看見沒有~ 每個葉子節點,都代表了一個字元,1就是a和e的。2是b的,依次...省略ing
然後遍曆,左就是0,右就是1。
c的就是00, d的就是01,a的是100,b=11,e=101.這樣就成功了。
下面驗證成果:計算儲存空間。從a到e:3*1+2*2+2*3+2*4+3*1 = 24 bits。發現沒,少了整整9 bits,什麼概念?也就是說壓縮了接近1/3啊,假如3G大小,壓縮後就是2G了啊。
既然這麼好,下面附上代碼實現。
代碼實現
</pre><pre name="code" class="cpp">//// main.cpp// HuffmanCode//// Created by Alps on 14/11/22.// Copyright (c) 2014年 chen. All rights reserved.//#include <iostream>using namespace std;typedef struct HTNode{ int weight; int parent; int lchild; int rchild;}HTNode, *HuffmanTree;typedef char** HuffmanCode;void Select(HuffmanTree HT, int num, int &child1, int &child2);void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){ // int m,i; int child1,child2; if (n <= 1) { return; } m = n*2-1;//整棵樹的節點數 HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));//申請足夠空間 for (i = 1; i <= n; i++,w++) { HT[i] = {*w, 0, 0, 0}; } for (; i <= m; i++) { HT[i] = {0, 0, 0, 0}; } for (i = n+1; i <= m; i++) { Select(HT,i-1,child1,child2); HT[child1].parent = i; HT[child2].parent = i; HT[i].lchild = child1; HT[i].rchild = child2; HT[i].weight = HT[child1].weight + HT[child2].weight; printf("%d==%d\n",child1,child2); } HC = (char**)malloc((n+1)*sizeof(char *)); char *cd = (char*)malloc(n*sizeof(char));// memset(cd, '\0', n*sizeof(char)); int c = 0; int tempParent,count; for (i = 1; i <= n; i++) { count = 0; for (c = i,tempParent = HT[i].parent; tempParent != 0;c=tempParent, tempParent = HT[tempParent].parent) { if (HT[tempParent].lchild == c) { cd[count++] = '0'; }else{ cd[count++] = '1'; } } cd[count]='\0'; printf("%s~%d\n",cd,i); HC[i] = (char *)malloc((count)*sizeof(char)); for (int j = count; j>=0; j--) { HC[i][count-j] = cd[j-1]; }// memset(cd,'\0', n*sizeof(char));//error }}void Select(HuffmanTree HT, int num, int &child1, int &child2){ child1 = 0; child2 = 0; int w1 = 0; int w2 = 0; for (int i = 1; i <= num; i++) { if (HT[i].parent == 0) { if (child1 == 0) { child1 = i; w1 = HT[i].weight; continue; } if (child2 == 0) { child2 = i; w2 = HT[i].weight; continue; } if (w1 > w2 && w1 > HT[i].weight) { w1 = HT[i].weight; child1 = i; continue; } if (w2 > w1 && w2 > HT[i].weight) { w2 = HT[i].weight; child2 = i; continue; } } }}int main(int argc, const char * argv[]) { char a[] = "abcaab"; int i = (int)strlen(a); printf("%d\n",i); int b[]={1,2,3,4}; HuffmanTree HT; HuffmanCode HC; HuffmanCoding(HT, HC, b, 4); for (i = 1; i <= 7; i++) { printf("%d-%d\n",HT[i].weight,HT[i].parent); } for (i = 1; i <=4; i++) { printf("%s\n",HC[i]); } return 0;}