s2=i;
i++;
}
}
intHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn){//根据各个字符的权值构造赫夫曼树HT,将对应的赫夫曼编码存储在HC中
ints1,s2,m,i,start;
unsignedintc,f;
HTNode*p;
char*cd;
if(n<=1)return0;
m=2*n-1;//赫夫曼树的总结点树为m
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//申请存储赫夫曼树的空间
for(p=HT+1,i=1;i<=n;++i,++p,++w){//将各个叶子结点的weight赋以相应的权值,parent,lchild,rchild均赋为0
p->weight=*(w+1);
p->parent=p->lchild=p->rchild=0;
}
for(;i<=m;++i,++p){//将各个非叶子结点的weight,parent,lchild,rchild均赋为0
p->weight=p->parent=p->lchild=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;
}
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;//编码在数组cd[]中的最前位置
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));//为第i个字符编码分配空间
strcpy(HC[i],&cd[start]);//将cd[]数组的start位置到n-1位置复制给HC[i]
}
free(cd);//释放空间
return1;
}
以上为第一部分
#include
#include
#include"Huffman_Tree.h"
#defineYes1//当程序已经调用过初始化赫夫曼树的InitHuff_T()函数,或已从htfTree文件读取过,则将Init_Mode置为Yes,否则为No
#defineNo0
voidInitHuff_T(HuffmanTree&HT,HuffmanCode&HC,charch[],int&n){//初始化赫夫曼数,要求用户输入字符和相应权值
inti=1,w[100],tem,j;
chara[20];
FILE*save;
printf("请输入编码字符集的大小n:
");
scanf("%d",&n);//获取用户输入的字符集个数
while(i<=n){//获取用户输入的字符和相应权值,分别存储在ch[]和w[]数组中
printf("请输入第%d个字符和该字符的权值w:
",i);
fflush(stdin);
scanf("%c%d",&ch[i],&w[i]);
i++;
}
ch[i]='\0';
HuffmanCoding(HT,HC,w,n);//根据用户的输入,生成赫夫曼数及各个字符相应的赫夫曼编码,分别存在HT树和HC中
if((save=fopen("htfTree","w"))==NULL){//打开用于存储赫夫曼树的文件
printf("Openfilefail......\n");
exit(0);
}
tem=n;//接下来的14行是将字符集大小转换成字符形式写入到文件中
j=0;
while(tem!
=0){
tem=tem/10;
j++;
}
tem=n;
a[j]='\0';
while(tem!
=0){
a[j-1]=(char)(tem%10+48);
tem=tem/10;
j--;
}
fputs(a,save);
printf("%d\n",n);//向屏幕输出字符集大小n
fputc('\n',save);
for(i=1;i<=n;i++){//分别向文件和屏幕输出各个字符和相应的赫夫曼编码
fputc(ch[i],save);printf("%c\t",ch[i]);
fputc('\t',save);
fputs(HC[i],save);printf("%s\n",HC[i]);
fputc('\n',save);
}
for(i=1;i<=2*n-1;i++){//将赫夫曼树各个结点的parent,lchild,rchild分别写入到文件中
tem=HT[i].parent;//将i结点的parent转换成字符并写入到文件中
if(tem==0){
fputc(tem+48,save);
fputc('',save);
}
else{
j=0;
while(tem!
=0){
tem=tem/10;
j++;
}
tem=HT[i].parent;
a[j]='\0';
while(tem!
=0){
a[j-1]=(char)(tem%10+48);
tem=tem/10;
j--;
}
fputs(a,save);
fputc('',save);
}
tem=HT[i].lchild;//将i结点的lchild转换成字符并写入到文件中
if(tem==0){
fputc(tem+48,save);
fputc('',save);
}
else{
j=0;
while(tem!
=0){
tem=tem/10;
j++;
}
tem=HT[i].lchild;
a[j]='\0';
while(tem!
=0){
a[j-1]=(char)(tem%10+48);
tem=tem/10;
j--;
}
fputs(a,save);
fputc('',save);
}
tem=HT[i].rchild;//将i结点的rchild转换成字符并写入到文件中
if(tem==0){
fputc(tem+48,save);
fputc('\n',save);
}
else{
j=0;
while(tem!
=0){
tem=tem/10;
j++;
}
tem=HT[i].rchild;
a[j]='\0';
while(tem!
=0){
a[j-1]=(char)(tem%10+48);
tem=tem/10;
j--;
}
fputs(a,save);
fputc('\n',save);
}
}
fclose(save);
}
voidEncoding(HuffmanTree&HT,HuffmanCode&HC,charch[]){//根据赫夫曼编码将用户指定的文件中的字符编成相应的编码,并将所得编码存储到用户指定文件
FILE*ToBeTran,*CodeFile;
charToBeTran_Name[100],CodeFile_Name[100];//存储用户指定文件的文件名
inti;
charc;
printf("请输入所要进行编码的文件的文件名:
");
scanf("%s",ToBeTran_Name);//获得所要进行编码的文件的文件名
if((ToBeTran=fopen(ToBeTran_Name,"r"))==NULL){//打开文件
printf("Openfilefail......\n");
exit(0);
}
printf("请输入编码后编码表示的信息所存储到的文件的文件名:
");
scanf("%s",CodeFile_Name);//获得编码后编码表示的信息所存储到的文件的文件名
if((CodeFile=fopen(CodeFile_Name,"w"))==NULL){//打开文件
printf("Openfilefail......\n");
exit(0);
}
c=fgetc(ToBeTran);//从文件读取一个字符
while(c!
=EOF){//对文件中的各个字符进行编码,直至文件结尾
i=1;
while(c!
=ch[i]&&ch[i]!
='\0')//在ch[]数组中查找从文件读取的字符
i++;
if(ch[i]=='\0'){//未找到,c不在ch[]数组中,c无法被识别,程序出错,退出
printf("字符%c无法识别,程序将退出。
\n",c);
exit(0);
}
fputs(HC[i],CodeFile);//若找到,则将c相应的赫夫曼编码写入到文件中
printf("%s",HC[i]);//将c相应的赫夫曼编码输出到屏幕
c=fgetc(ToBeTran);//读入文件中的下一个字符
}
printf("\n");
fclose(ToBeTran);
fclose(CodeFile);
}
voidDecoding(HuffmanTreeHT,charch[],intn){//对指定的存储由赫夫曼编码表示的信息的文件进行译码,翻译成相应的字符表示,并存储到指定文件
intp,i=1;
charcode[1000],c;
charCodeFile_Name[100],TextFile_Name[100];//存储用户指定文件的文件名
p=2*n-1;
FILE*CodeFile,*TextFile;
printf("请输入所要译的文件名:
");
scanf("%s",CodeFile_Name);//获得所要译的文件的文件名
if((CodeFile=fopen("CodeFile","r"))==NULL){//打开文件
printf("Openfilefail......\n");
exit(0);
}
printf("请输入译后的字符存储到的文件的文件名:
");
scanf("%s",TextFile_Name);//获得译后的字符存储到的文件的文件名
if((TextFile=fopen(TextFile_Name,"w"))==NULL){//打开文件
printf("Openfilefail......\n");
exit(0);
}
c=fgetc(CodeFile);
while(c!
=EOF){
code[i]=c;
i++;
c=fgetc(CodeFile);
}
code[i]='\0';//从文件读取字符,存储在code[]数组中
i=1;
while(code[i]!
='\0'&&p!
=0){//对数组code[]中的赫夫曼编码进行译码
if(code[i]=='0')
p=HT[p].lchild;//进入左分支
else
p=HT[p].rchild;//进入右分支
if(!
HT[p].lchild&&!
HT[p].rchild){//进入叶子结点
fputc(ch[p],TextFile);//将相应的字符写入到文件中
printf("%c",ch[p]);//将相应的字符输出到屏幕
p=2*n-1;//重新从树根出发进行译码
}
i++;
}
printf("\n");
}
voidReadHuff_T(HuffmanTree&HT,HuffmanCode&HC,charch[],int&n){//从文件读取赫夫曼树
FILE*htfTree;
charc[100],ch1;
inti,j,t;
if((htfTree=fopen("htfTree","r"))==NULL){//打开存有赫夫曼树信息的文件
printf("Openfilefail......\n");
exit(0);
}
fgets(c,10,htfTree);//获取赫夫曼树叶子结点个数的字符串表示形式
i=0;//以下6行将字符串形式转换成整数形式
while(c[i]!
='\n')
i++;
n=0;
for(j=0;j
n=10*n+c[j]-'0';//求出叶子结点数n
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//申请HC空间
HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));//申请赫夫曼树存储空间
i=1;
while(i<=n){
ch[i]=fgetc(htfTree);//读取字符集中的一个字符
HC[i]=(char*)malloc((10)*sizeof(char));//申请用于存储读取到的字符集中的字符的赫夫曼编码的空间
fgetc(htfTree);//将‘\t’输出
ch1=fgetc(htfTree);//读取赫夫曼编码,存储在相应的HC[i][]数组里
intj=0;
while(ch1!
='\n'){
HC[i][j]=ch1;
j++;
ch1=fgetc(htfTree);
}
HC[i][j]='\0';
i++;
}
ch[i]='\0';
i=0;
while(i<2*n-1){//读取赫夫曼树的各个结点的parent,lchild,rchild.并赋值到赫夫曼树HT中
ch1=fgetc(htfTree);//读取parent的字符串形式,存储在c[]中,并将其转换成整数形式,赋给HT[i].parent
j=0;
while(ch1!
=''){
c[j]=ch1;
j++;
ch1=fgetc(htfTree);
}
HT[i+1].parent=0;
for(t=0;tHT[i+1].parent=10*HT[i+1].parent+c[t]-'0';
ch1=fgetc(htfTree);//读取lchild的字符串形式,并将其转换成整数形式,赋给HT[i].lchild
j=0;
while(ch1!
=''){
c[j]=ch1;
j++;
ch1=fgetc(htfTree);
}
HT[i+1].lchild=0;
for(t=0;tHT[i+1].lchild=10*HT[i+1].lchild+c[t]-'0';
ch1=fgetc(htfTree);//读取rchild的字符串形式,并将其转换成整数形式,赋给HT[i].rchild
j=0;
while(ch1!
='\n'){
c[j]=ch1;
j++;
ch1=fgetc(htfTree);
}
HT[i+1].rchild=0;
for(t=0;tHT[i+1].rchild=10*HT[i+1].rchild+c[t]-'0';
i++;
}
}
intmain(){
HuffmanTreeHT;
HuffmanCodeHC;
charch[100];//用于存储字符集
intn,Init_Mode=No;//n为字符集的大小,Init_Mode=No表示内存中没有赫夫曼树的信息
charmode;//让用户选择不同的操作
printf("请输入你要选择的功能\n");
printf("\t\tI--初始化\t\tE--编码\n");
printf("\t\tD--译码\t\tQ--退出程序\n");
scanf("%c",&mode);//获得用户选择的操作
while(mode!
='Q'&&mode!
='q'){//当用户输入不为Q或q时,执行相应操作
switch(mode){
case'I':
InitHuff_T(HT,HC,ch,n);
Init_Mode=Yes;
break;
case'i':
InitHuff_T(HT,HC,ch,n);
Init_Mode=Yes;
break;
case'E':
if(No==Init_Mode)
ReadHuff_T(HT,HC,ch,n);
Encoding(HT,HC,ch);
Init_Mode=Yes;
break;
case'e':
if(No==Init_Mode)
ReadHuff_T(HT,HC,ch,n);
Encoding(HT,HC,ch);
Init_Mode=Yes;
break;
case'D':
if(No==Init_Mode)
ReadHuff_T(HT,HC,ch,n);
Decoding(HT,ch,n);
Init_Mode=Yes;
break;
case'd':
if(No==Init_Mode)
ReadHuff_T(HT,HC,ch,n);
Decoding(HT,ch,n);
Init_Mode=Yes;
default:
printf("您的输入有错,请重新选择.\n");
}
printf("请输入你要选择的功能\n");
printf("\tI--初始化\tE--编码\n");
printf("\tD--译码\tQ--退出程序\n");
fflush(stdin);
scanf("%c",&mode);//让用户继续选择相应的操作,直至用户选择退出
}
return0;
}