Huffman編碼
阿新 • • 發佈:2020-12-05
Huffman編碼
哈夫曼編碼(Huffman Coding),是一種編碼方式,哈夫曼編碼是可變字長編碼(VLC)的一種。Huffman於1952年提出一種編碼方法,該方法完全依據字元出現概率來構造異字頭的平均長度最短的碼字,有時稱之為最佳編碼,一般就叫做Huffman編碼 。
-
預備知識
-
哈夫曼樹的儲存結構
typedef struct
{
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode,*HuffmanTree; //動態分配陣列儲存哈夫曼樹
-
哈夫曼編碼的儲存結構
typedef char * *HuffmanCode;
//動態分配陣列儲存哈夫曼編碼表
-
-
實驗題目
從鍵盤接收任意一個字串。以字串中某字元出現的次數,作為該字元的權值。利用得到的權值構造huffman樹、並輸出每個字元對應的huffman編碼。
程式碼執行的預編譯命令
#include <stdio.h>
#include <malloc.h>
#include <string.h>
所用的函式的宣告以及結構體定義
#include "CommonDef.h" typedef struct{ int weight; int parent,lchild,rchild; }HTNode,*HuffmanTree; typedef struct{ char ch; int weight; }ww,*W; typedef char **HuffmanCode; void select(HuffmanTree *HT,int n,int *s1,int *s2); void HuffmanCoding(HuffmanTree *HT,W *w,int n); void Huffman(HuffmanTree HT,HuffmanCode *HC,W *w,int n);
具體的函式實現
Huffman樹的構建
void HuffmanCoding(HuffmanTree *HT,W *w,int n){ HuffmanTree p; int s1,s2,m,i; if(n<=1) return; m=2*n-1; *HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(p=*HT+1,i=1;i<=n;i++,p++){ p->weight=w[i-1]->weight; p->lchild=0; p->parent=0; p->rchild=0; } for(;i<=m;i++,p++){ p->weight=0; p->lchild=0; p->parent=0; p->rchild=0; } for(i=n+1;i<=m;i++){ select(HT,i-1,&s1,&s2); (*HT)[s1].parent=i; (*HT)[s2].parent=i; (*HT)[i].lchild=s1;(*HT)[i].rchild=s2; (*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight; } for(p=*HT+1,i=1;i<=m;i++){ printf("%d %d %d %d\n",p->weight,p->parent,p->lchild,p->rchild); p++; } }
構建Huffman樹中找查最小值與次小值的實現
void select(HuffmanTree *HT,int n,int *s1,int *s2){
int i=1,min,cmin;
HuffmanTree p;
p=*HT+1;
while(p->parent!=0){
p++;
i++;}
min=p->weight;*s1=i;//最小
p++;i++;
while(p->parent!=0){
p++;
i++;}
cmin=p->weight;*s2=i;//次小
for(i=1,p=*HT+1;i<=n;i++,p++){
if(p->parent==0){
if(p->weight<min){
cmin=min;
min=p->weight;
*s2=*s1;
*s1=i;
}
else if(p->weight<cmin&&(*s1!=i)){
cmin=p->weight;
*s2=i;
}
}
}
}
通過Huffman樹實現Huffman編碼
void Huffman(HuffmanTree HT,HuffmanCode *HC,W *w,int n){
char *cd;
int i,start,c,f;
*HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
cd=(char *)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=1;i<=n;i++){
start=n-1;
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
if(HT[f].lchild==c) cd[--start]='0';
else cd[--start]='1';
}
(*HC)[i]=(char *)malloc((n-start)*sizeof(char));
strcpy((*HC)[i],&cd[start]);
}
free(cd);
}
測試程式碼
int main(){
W w[26];
int n,n1,i,j;
int zifu[26]={0};
char *s;
FILE *fp1,*fp2;
HuffmanTree HT;
HuffmanCode HC;
s=(char *)malloc(100*sizeof(char));
fp1=fopen("input.txt","r");
fp2=fopen("output.txt","w");
if(!fp1)
{
printf("can't open file\n");
return -1;
}
fscanf (fp1,"%s",s);
n=strlen(s);
for(i=0;i<26;i++){
w[i]=(W)malloc(sizeof(ww));//結構體陣列分配空間
}
for(i=0;i<n;i++){
zifu[s[i]-'a']++;
}
for(i=0,j=0;i<26;i++){
if(zifu[i]!=0){
w[j]->ch=i+'a';
w[j]->weight=zifu[i];//給每個陣列賦值
j++;
}
}
n1=j;
for(i=0;i<n1;i++){
printf("%c的權值%d\n",w[i]->ch,w[i]->weight);
fprintf(fp2,"%c的權值%d\n",w[i]->ch,w[i]->weight);
}
HuffmanCoding(&HT,w,n1);
Huffman(HT,&HC,w,n1);
for(i=1;i<=n1;i++){
printf("%c的編碼:%s\n",w[i-1]->ch,(HC)[i]);
fprintf(fp2,"%c的編碼:%s\n",w[i-1]->ch,(HC)[i]);
}
return 0;
}
一些注意事項
-
測試程式碼中的資料是從檔案讀入,然後再寫入檔案中。讀入的檔案全為字母,我的測試資料中全用的小寫字母。
-
程式碼首先對讀入字母進行統計出現的個數,然後再實現編碼。
-
本來只把算出來的編碼寫入檔案中,但是為了更好觀看,也列印在螢幕中了。
-
本來程式碼中無法對應每個字母,如圖
為了更好看出每個字母對應的編碼,採用了結構體來儲存每個字母的權值,這樣既可以儲存權值,也可以把字母儲存進去。
測試資料
-
input檔案的資料: aaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccddddddddeeeeeeeeeeeeeefffffffffffffffffffffffggghhhhhhhhhhh
-
所得到的Huffman編碼