信息论霍夫曼编码译码实验报告.docx
《信息论霍夫曼编码译码实验报告.docx》由会员分享,可在线阅读,更多相关《信息论霍夫曼编码译码实验报告.docx(7页珍藏版)》请在冰豆网上搜索。
信息论霍夫曼编码译码实验报告
实验一
一、实验背景
*哈夫曼编码(HuffmanCoding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。
Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般叫作Huffman编码。
二、实验要求
*利用程序实现哈夫曼编码,以加深对哈夫曼编码的理解,并锻炼编程能力。
三、代码分析
#include
#definen3//叶子数目
#definem(2*n-1)//结点总数
#definemaxval10000.0//maxval是float类型的最大值
#definemaxsize100//哈夫曼编码的最大位数
typedefstruct//定义霍夫曼树结构体
{
charch;//消息
floatweight;//所占权重
intlchild,rchild,parent;//定义左孩子、右孩子
}hufmtree;
typedefstruct//定义霍夫曼编码结构体
{
charbits[n];//位串
intstart;//编码在位串中的起始位置
charch;//字符
}codetype;
voidhuffman(hufmtreetree[]);//建立哈夫曼树
voidhuffmancode(codetypecode[],hufmtreetree[]);//根据哈夫曼树求出哈夫曼编码
voiddecode(hufmtreetree[]);//依次读入电文,根据哈夫曼树译码
voidmain()
{
printf("——哈夫曼编码——\n");
printf("信源共有%d个符号\n",n);
hufmtreetree[m];//m个结点,即有m个树形结构
codetypecode[n];//信源有n个消息,则需要n个编码
inti,j;//循环变量
huffman(tree);//建立哈夫曼树
huffmancode(code,tree);//根据哈夫曼树求出哈夫曼编码
printf("【输出每个字符的哈夫曼编码】\n");
for(i=0;i{
printf("%c:
",code[i].ch);
for(j=code[i].start;jprintf("%c",code[i].bits[j]);
//“消息:
该消息的编码”
printf("\n");
}
printf("【读入电文,并进行译码】\n");
decode(tree);//依次读入电文,根据哈夫曼树译码
}
voidhuffman(hufmtreetree[])//建立哈夫曼树
{
inti,j,p1,p2;//p1,p2分别记住每次合并时权值最小和次小的两个根结点的下标
floatsmall1,small2,f;
charc;
for(i=0;i{
tree[i].parent=0;
tree[i].lchild=-1;
tree[i].rchild=-1;
tree[i].weight=0.0;
}
printf("【依次读入前%d个结点的字符及权值(中间用空格隔开)】\n",n);
for(i=0;i{
printf("输入第%d个字符为和权值",i+1);
scanf("%c%f",&c,&f);
getchar();//吸收回车符
tree[i].ch=c;
tree[i].weight=f;//将接收到的结点的字符及权值存入它对应的结构体数据中
}
for(i=n;i{
p1=0;p2=0;
small1=maxval;small2=maxval;//maxval是float类型的最大值
for(j=0;j
{
if(tree[j].parent==0)//还未找到父结点的
if(tree[j].weight{
small2=small1;//改变最小权、次小权及对应的位置
small1=tree[j].weight;
p2=p1;
p1=j;
}
elseif(tree[j].weight{
small2=tree[j].weight;//改变次小权及位置
p2=j;
}
}
//找出的两个结点是新节点i的两个孩子
tree[p1].parent=i;
tree[p2].parent=i;
tree[i].lchild=p1;//最小权根结点是新结点的左孩子
tree[i].rchild=p2;//次小权根结点是新结点的右孩子
tree[i].weight=tree[p1].weight+tree[p2].weight;
}
}//huffman
//codetypecode[]为求出的哈夫曼编码
//hufmtreetree[]为已知的哈夫曼树
voidhuffmancode(codetypecode[],hufmtreetree[])//根据哈夫曼树求出哈夫曼编码
{
inti,c,p;
codetypecd;//缓冲变量
for(i=0;i{
cd.start=n;//编码在位串中的起始位置
cd.ch=tree[i].ch;
c=i;//从叶结点出发向上回溯,第i个叶结点
p=tree[i].parent;//tree[p]是tree[i]的父结点
while(p!
=0)
{
cd.start--;
if(tree[p].lchild==c)
cd.bits[cd.start]='0';//tree[i]是左子树,生成代码'0'else
cd.bits[cd.start]='1';//tree[i]是右子树,生成代码'1'c=p;//c记录此时的父结点
p=tree[p].parent;//p记录新的父结点,即原来的父结点的父结点,向上溯回
}
code[i]=cd;//第i+1个字符的编码存入code[i]}
}//huffmancode
voiddecode(hufmtreetree[])//依次读入电文,根据哈夫曼树译码{
inti,j=0;
charb[maxsize];
i=m-1;//从根结点开始往下搜索
printf("输入发送的编码:
");
gets(b);
printf("译码后的字符为");
while(b[j]!
='\0')
{
if(b[j]=='0')
i=tree[i].lchild;//走向左子树
else
i=tree[i].rchild;//走向右子树
if(tree[i].lchild==-1)//如果回到叶结点,则把该结点的消息符号输出
{
printf("%c",tree[i].ch);
i=m-1;//回到根结点
}
j++;
}
printf("\n");
if(tree[i].lchild!
=-1&&b[j]=='\0')//电文读完,但尚未到叶子结点printf("\nERROR\n");//输入电文有错
}//decode
四、实验补充说明
解码时,以回车键结束输入电文。
已修复“电文读完,但尚未到叶子结点”这种情况下不能显示”ERROR”的错误。
构建父结点时,使用的序号i是在[n,m-1]的,最初的消息在结点的序号在[0,n-1],每次寻找新的父结点,都是从0到i寻找,所以就是会优先叶子结点进行合并,所以这是一种方差最小的最优霍夫曼编码。