這一節介紹哈夫曼樹和哈弗曼編碼,其中構造哈弗曼樹的步驟如下
1.根據給定的n個權值{ Wl,響,…,Wn }構成n棵二叉樹的集合F={Tl,T2,…Tn},其中每棵二叉樹Ti 中只有一個帶權爲Wi 根結點,其左右子樹均爲空。
2. 在F中選取兩棵根結點的權值最小的樹作爲左右子樹構造一棵新的二叉樹,且置新的二叉樹的根結點的權值爲其左右子樹上根結點的權值之和。
3. 在F中刪除這兩棵樹,同時將新得到的二叉樹加入F中。
4. 重複2和3步驟,直到F只含一棵樹爲止。這棵樹便是哈弗曼樹。
對於哈弗曼編碼是一種最基本的壓縮編碼方式,就是根據哈弗曼樹,然後前綴編碼,左子樹爲0,右子樹爲1
實現的代碼是參考http://www.cnblogs.com/Jezze/archive/2011/12/23/2299884.html,感覺代碼讀起來易懂
我知識調整了下代碼的結構,讓代碼更加清晰,還有刪去了源代碼的解碼函數,但是核心代碼都沒有變化,其中關於如何求權值可以使用優先隊列,參考九度題目1172:哈夫曼樹
代碼中用的是實現二叉樹的另外一種存儲結構,雙親表示法,其實感覺這個雙親表示法的思想和靜態鏈表的思想類似
struct haTree{
int parent; //存儲該結點的雙親在數組中的下標
int lchild;
int rchild;
int weight; //權重
};
struct haCode{
int bit[MAXN]; //編碼數組
int start; //編碼起始長度,作用就是知道當前結點的編碼長度
};
struct haTree h[MAXN];
創建哈弗曼樹的代碼如下:
void creatHuffmanTree(struct haTree *h,int n){
int i,j;
int m=2*n-1;
for(i=0;i<m;i++){
h[i].parent=-1;
h[i].lchild=-1;
h[i].rchild=-1;
h[i].weight=-1;
}
for(i=0;i<n;i++) scanf("%d",&h[i].weight);
int x1,x2;
int m1,m2;
for(i=0;i<n-1;i++){
x1=x2=0; //x1,x2分別爲最小的兩個結點的下標
m1=m2=MAX;
for(j=0;j<n+i;j++){
if(h[j].weight<m1&&h[j].parent==-1){ //查找當前最小的權值的結點
m2=m1;
x2=x1;
x1=j;
m1=h[j].weight;
}
else if(h[j].weight<m2&&h[j].parent==-1){ //查找當前倒數第二小的權值的結點
x2=j;
m2=h[j].weight;
}
}
h[x1].parent=n+i;
h[x2].parent=n+i;
h[n+i].weight=h[x1].weight+h[x2].weight;
h[n+i].lchild=x1;
h[n+i].rchild=x2;
printf ("x1.weight and x2.weight in round %d: %d, %d\n", i+1, h[x1].weight, h[x2].weight);
printf ("\n");
}
for(i=0;i<n+2;i++)
{
printf("Parents:%d,lchild:%d,rchild:%d,weight:%d\n",h[i].parent,h[i].lchild,h[i].rchild,h[i].weight);
}
}
創建哈弗曼編碼的代碼如下
void HuffmanCode(struct haCode *huffCode,int n){
int i,p,j,c;
struct haCode tmp;
for(i=0;i<n;i++){
tmp.start=n-1;
c=i;
p=h[c].parent;
while(p!=-1){ //對每個結點編碼,n-(start+1)爲編碼位的數目,如n=4,編碼是011(編碼最多是n-1位),則start=0
if(h[p].lchild==c) tmp.bit[tmp.start]=0;
else tmp.bit[tmp.start]=1;
tmp.start--;
c=p;
p=h[c].parent;
}
for(j=tmp.start+1;j<n;j++) huffCode[i].bit[j]=tmp.bit[j];
huffCode[i].start=tmp.start;
}
}
總的代碼如下:
#include <stdio.h>
#define MAXN 100
#define MAX 1000000
struct haTree{
int parent;
int lchild;
int rchild;
int weight;
};
struct haCode{
int bit[MAXN];
int start;
};
struct haTree h[MAXN];
void creatHuffmanTree(struct haTree *h,int n){
int i,j;
int m=2*n-1;
for(i=0;i<m;i++){
h[i].parent=-1;
h[i].lchild=-1;
h[i].rchild=-1;
h[i].weight=-1;
}
for(i=0;i<n;i++) scanf("%d",&h[i].weight);
int x1,x2;
int m1,m2;
for(i=0;i<n-1;i++){
x1=x2=0; //x1,x2分別爲最小的兩個結點的下標
m1=m2=MAX;
for(j=0;j<n+i;j++){
if(h[j].weight<m1&&h[j].parent==-1){ //查找當前最小的權值的結點
m2=m1;
x2=x1;
x1=j;
m1=h[j].weight;
}
else if(h[j].weight<m2&&h[j].parent==-1){ //查找當前倒數第二小的權值的結點
x2=j;
m2=h[j].weight;
}
}
h[x1].parent=n+i;
h[x2].parent=n+i;
h[n+i].weight=h[x1].weight+h[x2].weight;
h[n+i].lchild=x1;
h[n+i].rchild=x2;
printf ("x1.weight and x2.weight in round %d: %d, %d\n", i+1, h[x1].weight, h[x2].weight);
printf ("\n");
}
for(i=0;i<n+2;i++)
{
printf("Parents:%d,lchild:%d,rchild:%d,weight:%d\n",h[i].parent,h[i].lchild,h[i].rchild,h[i].weight);
}
}
void HuffmanCode(struct haCode *huffCode,int n){
int i,p,j,c;
struct haCode tmp;
for(i=0;i<n;i++){
tmp.start=n-1;
c=i;
p=h[c].parent;
while(p!=-1){ //對每個結點編碼,n-(start+1)爲編碼位的數目,如n=4,編碼是011(編碼最多是n-1位),則start=0
if(h[p].lchild==c) tmp.bit[tmp.start]=0;
else tmp.bit[tmp.start]=1;
tmp.start--;
c=p;
p=h[c].parent;
}
for(j=tmp.start+1;j<n;j++) huffCode[i].bit[j]=tmp.bit[j];
huffCode[i].start=tmp.start;
}
}
void display(struct haCode *huffCode,int n){
int i,j;
for(i=0;i<n;i++){
printf ("%d 's Huffman code is: ", i);
for(j=huffCode[i].start+1;j<n;j++){
printf("%d",huffCode[i].bit[j]);
}
printf(" start:%d\n",huffCode[i].start);
}
}
int main(){
int n;
scanf("%d",&n);
creatHuffmanTree(h,n);
struct haCode huffCode[MAXN];
HuffmanCode(huffCode,n);
display(huffCode,n);
return 0;
}