实现霍夫曼编解码的 C 源程序如下:(验证结果见附图)
#include
#include
#include
#include
#define N 16000
#define m 128
#define M 2*m-1
char CH[N];
char YW[N];
typedef char * Hcode[m+1]; //存放哈夫曼字符编码串的头指针的数组
typedef struct
{
//叶子结点个数,即字符总类数
//哈夫曼树的节点数
//记录原文字符数组
//记录译文字符数组
char a;
int num;
}dangenode;
typedef struct
{
dangenode b[129];
int tag;
}jilunode;
typedef struct node
{
int weight;
int parent;
int Lchild;
int Rchild;
}htnode,hn[M];
//记录单个字符的类别和出现的次数
//统计原文出现的字符种类数
//结点权值
//双亲下标
//左孩子结点的下标
//右孩子的下标
//静态三叉的哈夫曼树的定义
/*
主函数
*/
void main()
{
void jianliwenjian();
void luruyuanwen();
void min_2(hn ht,int n,int *tag1,int *tag2);
/*建立文件函数声明*/
/*录入函数声明*/
/*选择权值最小的结点函数声明
void chuangjian(jilunode * jilu,hn ht,float gailv[128],int * ppt);
/*建立哈弗曼函数声明
*/
*/
void bianma(jilunode * jilu,hn ht,Hcode hc,int n,int kk[129]);
void bianmabaocun(Hcode hc,jilunode * jilu);
void yiwen(Hcode hc,jilunode * jilu);
void baocunyiwen();
/*编码函数声明*/
/*保存编码函数声明*/
/*译文函数声明*/
/*保存译文函数声明*/
/*读取译文函数声明*/
/*读取译文函数声明*/
/*读取译码函数声明*/
//定义用三叉链表方式实现的哈夫曼树
//定义存放哈夫曼字符编码串的头指针的数组
//定义存放字符种类数量的栈
void duquyiwen();
void duquyuanwen();
void duqubianma();
int a,c,tep=1,qqq,ss;
int *ppt;
int kk[129];
char ww;
float abc1,gailv[m],sumc=0,jieguo=0,HH=0;
ppt=&ss;
hn humtree;
Hcode hc;
jilunode ji;
jilunode *jilu;
jilu=&ji;
jilu->tag=0;
while(tep)
{
printf("
printf("\n");
//取指针
//字符种类数标志初始化
$$$$$ 欢迎使用哈夫曼编码系统 $$$$$ \n");
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$$$$$$\n");
printf("\n");
printf("
printf("
printf("
printf("
printf("
printf("
printf("
printf("
printf("
printf("\n");
1--创建存贮原文件的文件\n");
2--输入原文\n");
3--对原文编码\n");
4--对编码译码\n");
5--输出原文\n");
6--输出译码\n");
7--输出译文\n");
8--输出编码效率\n");
0--退出\n");
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
请输入服务选项(数字):
$$$$$$$$$$$\n");
printf("\n");
printf("
a=0;
scanf("%d",&a);
getchar();
switch(a)
{
case 1:
");
case 2:
//建立存储字符的文件
jianliwenjian();
printf("是否继续?(YES :1 ,NO :0 ):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
goto LABLE;
system("cls");
break;
//将原文录入到文件中
system("cls");
luruyuanwen();
printf("\n 注意:原文件将保存在名称为 yuanwen 的文件中!\n");
printf("\n 注意:文件保存在 yuanwen 的文件中!\n");
printf("是否继续?(YES :1,NO :0 ):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
goto LABLE;
system("cls");
break;
case 3:
//创建哈夫曼树
//对哈夫曼树的叶子结点编码
system("cls");
chuangjian(jilu,humtree,gailv,ppt);
printf("\n 各字符编码结果为:\n");
bianma(jilu,humtree,hc,jilu->tag,kk);
printf("原文的编码为:\n");
printf("\n");
bianmabaocun(hc,jilu);
printf("\n");
printf("\n 注意:原文的编码将保存在以名称为 yiwen 的文件中!\n");
printf("是否继续?(YES :1 ,NO :0 ):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
//保存编码
goto LABLE;
system("cls");
break;
case 4:
system("cls");
printf("编码对应的译文为:\n");
yiwen(hc,jilu);
baocunyiwen();
printf("\n 注意:译文将保存在以名称为 textfile 的文件中!\n");
printf("是否继续?(YES :1,NO :0):");
//对编码译码
//保存译文
scanf("%d",&c);
ww=getchar();
if(ww=='n')
goto LABLE;
system("cls");
break;
case 5:
system("cls");
printf("原文为:\n");
duquyuanwen();
printf("是否继续?(YES :1,NO :0 ):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
//从文件中读取原文
goto LABLE;
system("cls");
break;
case 6:
system("cls");
printf("原文的编码为:\n");
duqubianma();
printf("是否继续?(YES :1,NO :0):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
//从文件中读取编码
goto LABLE;
system("cls");
break;
case 7:
system("cls");
printf("编码的译文为:\n");
duquyiwen();
printf("是否继续?(YES :1,NO :0 ):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
//从文件中读取译文
goto LABLE;
system("cls");
break;
case 8:
system("cls");
for(qqq=1;qqq<=ss;qqq++)
{
sumc=sumc+(gailv[qqq]*kk[qqq]);
}
printf("平均码长: %f",sumc);
for(qqq=1;qqq<=ss-1;qqq++)
{
HH=HH-((gailv[qqq])*((log(gailv[qqq]))/(log(2))));
}
printf("\n");
printf("信源熵为: %f",HH);
jieguo=HH/sumc;
printf("\n");
printf("编码效率为: %f",jieguo);
printf("\n");
printf("是否继续?(YES :1,NO :0 ):");
scanf("%d",&c);
ww=getchar();
if(ww=='n')
goto LABLE;
system("cls");
break;
LABLE:case 0:
system("cls");
printf("\n");
printf("\n");
printf("\n");
printf("
printf("\n");
printf("
printf("\n");
printf("
printf("\n");
printf("\n");
printf("\n");
printf("\n");
tep=0;
break;
system("cls");
printf("
printf("\n");
default:
}
}
}
再见! ");
BYEBYE!\n");
Welcome To See You Again!\n");
选择错误!\n");
void jianliwenjian()
{
printf("现在建立文件,以存储原文:\n");
printf("
FILE *fp;
if((fp=fopen("yuanwen","wb"))==NULL)
{
文件建立中......\n");
printf("Cannot open file\n");
exit(0);
//建立文件
}
printf("文件已建立,名称为:yuanwen");
fclose(fp);
//关闭文件
}
void luruyuanwen()
{
//原文输入完后,将其保存到文件 yuanwen 中
//打开文件
char ch;
FILE *fp;
if((fp=fopen("yuanwen","wb"))==NULL)
{
printf("Cannot open file\n");
exit(0);
}
printf("请输入原文(结束标志为#)\n");
do
{
ch=getchar();
fputc(ch,fp);
}while(ch!='#');
getchar();
fclose(fp);
}
//将字符保存到文件中
//判断结束
//接收回车命令符
//关闭文件
void min_2(hn ht,int n,int *tag1,int *tag2)//在建哈夫曼树的过程中,选择权值小的两
{
//个结点
int i,min,s;
min=N;
for(i=1;i<=n;i++)
if(ht[i].weight
min=ht[i].weight;
*tag1=i;
//记录权值最小的结点下标
}
min=N;
for(i=1;i<=n;i++)
if(ht[i].weighttag;j++)
{
if(CH[i]==jilu->b[j].a)
{
jilu->b[j].num++;
break;
}
/* 统计每个符号的出现的次数,并记录到*jilu 中去 */
}
if(j-1==jilu->tag&&CH[i]!=jilu->b[j-1].a)
{
jilu->tag++;
jilu->b[jilu->tag].a=CH[i];
jilu->b[jilu->tag].num=1;
}
}
}
jilu->tag--;
*ppt=jilu->tag;
fclose(fp);
printf("原文中的各字符统计状况如下:\n");
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
for(i=1;i<=jilu->tag;i++)
{
//关闭文件
s++;
printf("'%c'的个数为:%d
if(s%4==0)
printf("\n");
SUMF+=jilu->b[i].num;
zong[i]=jilu->b[i].num;
",jilu->b[i].a,jilu->b[i].num);
//每行放四个数据
/*统计字符总数*/
}
printf("\n");
printf(" 源文件字符总数为 : %d",SUMF);
printf("\n");
for(i=1;i<=jilu->tag;i++)
/*概率统计*/
{
/*打印字符总数*/
gailv[i]=zong[i]/(float)SUMF;
printf("%c 字符出现的概率为: %f
",jilu->b[i].a,gailv[i]);
}
printf("\n");
for(i=1;i<=2*(jilu->tag)-1;i++)
{
if(i<=jilu->tag)
{
ht[i].weight=jilu->b[i].num;
ht[i].Lchild=0;
ht[i].parent=0;
ht[i].Rchild=0;
//初始化叶子结点权值
//初始化叶子结点左孩子
//初始化叶子结点父母
//初始化叶子结点右孩子