#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define n 100
#define m 2*n-1
typedef struct {
char ch;
char bits[9];
int len;
}CodeNode;
typedef CodeNode HuffmanCode[n+1];
typedef struct {
int weight; //權值
int lchild,rchild,parent; //左右孩子及雙親指針
}HTNode;
typedef HTNode HuffmanTree[m+1];//0號單元不可用
int num;
void select(HuffmanTree T,int k,int &s1,int &s2)
{//在HT[1..k]中選擇parent爲0且權值最小的兩個根結點,
//其序號分別爲s1和s2
int i,j;int min1=101;
for(i=1;i<=k;i++)
if(T[i].weight<min1 && T[i].parent==0)
{
j=i;min1=T[i].weight;
}
s1=j;min1=32767;
for(i=1;i<=k;i++)
if(T[i].weight<min1 && T[i].parent==0 && i!=s1)
{
j=i;min1=T[i].weight;
}
s2=j;
}
int jsq(char *s,int cnt[],char str[])
{//統計字符串中各種字母的個數以及字符的種類
char *p;
int i,j,k;
int temp[27];
for(i=1;i<=26;i++)
temp[i]=0;
for(p=s;*p!='\0';p++)
{//統計各種字符的個數
if(*p>='A' && *p<='z'){
k=*p-64;
temp[k]++;
}
}
j=0;
for(i=1,j=0;i<=26;i++) //統計有多少種字符
if(temp[i]!=0){
j++;
str[j]=i+64; //送對應字母到數組中
cnt[j]=temp[i];//存入對應字母的權值
}
return j;
}
void ChuffmanTree(HuffmanTree HT,HuffmanCode HC,int cnt[],char str[])
{//構造赫夫曼樹HT
int i,s1,s2;
for(i=1;i<=2*num-1;i++) //初始化HT
{ HT[i].lchild=0;HT[i].rchild=0;
HT[i].parent=0;HT[i].weight=0;
}
for(i=1;i<=num;i++) //輸入num個葉結點的權值
HT[i].weight=cnt[i];
for(i=num+1;i<=2*num-1;i++)
{ //在HT[1..-1]中選擇parent爲0且權值最小的兩個根結點,
//其序號分別爲s1和s2);
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(i=0;i<=num;i++) //輸入字符集中的字符
HC[i].ch=str[i];
i=1;while(i<=num)
printf("字符%c,次數爲:%d\n",HC[i].ch,cnt[i++]);
}
void HuffmanEncoding(HuffmanTree HT, HuffmanCode HC)
{//根據赫夫曼樹HT求赫夫曼樹編碼HC
int c,p,i; //c和p分別指示T中孩子和雙親的位置
char cd[n]; //臨時存放編碼串
int start; //指示編碼在cd中起始位置
cd[num]='\0'; //最後一位放上串結束符
for(i=1;i<=num;i++)
{
start=num; //初始位置
c=i;
while((p=HT[c].parent)>0) //直至上溯到HT[c]及樹根爲止
{//若T[c]是T[p]的左孩子,則生成代碼1
cd[--start]=(HT[p].lchild==c)?'0':'1';
c=p;
}//end or while
strcpy(HC[i].bits,&cd[start]);
HC[i].len=num-start;
}//end or for
}
void coding(HuffmanCode HC,char *str)
{//對str所代表的字符串進行編碼,並寫入文件
int i,j;
FILE *fp;
fp=fopen("codefile.txt","w");
while(*str){
for(i=1;i<=num;i++)
if(HC[i].ch==*str){
for(j=0;j<HC[i].len;j++)
fputc(HC[i].bits[j],fp);
break;
}
str++;
}
fclose(fp);
}
char *decode(HuffmanCode HC)
{//代碼文件codefile.txt的譯碼
FILE *fp;
char str[254]; //假設原文件不超過254個字符
char *p;
static char cd[n+1];
int i,j,k=0,cjs;
fp=fopen("codefile.txt","r");
while(!feof(fp))
{
cjs=0;
for(i=0;i<num && cjs==0 && !feof(fp);i++)
{
cd[i]=' ';cd[i+1]='\0';
cd[i]=fgetc(fp);
for(j=1;j<=num;j++)
if(strcmp(HC[j].bits,cd)==0)
{
str[k]=HC[j].ch;k++;
cjs=1;break;
}
}
}
str[k]='\0';p=str;
return p;
}
void main()
{
char st[254],*s,str[27];
int cn[27];
HuffmanTree HT;
HuffmanCode HC;
printf("輸入需要編碼的字符串(假設均爲大寫字母):\n");
gets(st);
num=jsq(st,cn,str); //統計字符的種類及各類字符出現的頻率
ChuffmanTree(HT,HC,cn,str); //建立赫夫曼樹
HuffmanEncoding (HT,HC); //生成赫夫曼樹
coding(HC,st); //建立電文赫夫曼編碼文件
s=decode(HC); //讀編碼文件譯碼
printf("譯碼後的字符串:\n");
printf("%s\n",st); //輸出譯碼後字符串
}
Huffman編碼問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.