哈夫曼树的应用与实现

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/*哈夫曼树的应用和实现
(1)根据输入的字符和相应的权值建立哈夫曼树,并输出已建的相应内容作
为检查;
(2)用哈夫曼树实现前缀编码,并输出各字符的编码串;
(3)输入一组二进制报文,进行译码,并输出译文。

*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define N 1000 //定义结点数最大值
#define M 2*N-1
#define maxval 10000.0 //定义float的最大值
typedef struct //定义哈夫曼树类型
{
char data;
float weight;
int lchild,rchild,parent;
}hufmtree;
hufmtree tree[M];
typedef struct //定义哈夫曼树编码类型
{
char bits[N];
int start;
char data;
}codetype;
codetype code[N];
void HUFFMAN(hufmtree t[]);
void HUFFMANCODE(codetype code[],hufmtree t[]);
void HUFFMANDECODE(codetype code[],hufmtree t[]);
void OUTTREE(hufmtree t[]);
static int n,m; //定义静态全局变量n储存需要的结点数
//m为构建哈夫曼树后的总结点数
//菜单的建立
void main()
{
int x,flag1=0;
printf("\t\t\t哈夫曼树的应用和实现\n");
while(1)
{
printf("——————————————————————————————————\n");
printf("菜单:1 建立哈夫曼树 2 哈夫曼树编码 3 输入电文译码0 退出使用\n");
printf("——————————————————————————————————\n");
printf("请选择操作:\n");
scanf("%d",&x);
switch(x)
{
case 1:
HUFFMAN(tree);
break;
case 2:
HUFFMANCODE(code,tree);
break;
case 3:
HUFFMANDECODE(code,tree);
break;
case 0:
flag1=1; //输入号为0时使flag1=1
break;
default:
printf("输入的选择有误!请重新输入!\n");
break;
}
if(flag1) break; //表明选择了退出操作故跳出循环
}
printf("Thank You!\n");
}
//哈夫曼树的构建
void HUFFMAN(hufmtree t[])
{
int i,j,p1,p2;
char ch;
float small1,small2,f;
printf("请输入叶子结点数:\n");
scanf("%d",&n);
m=2*n-1;
for(i=0;i<m;i++) //初始化哈夫曼树
{
tree[i].parent=0;
tree[i].lchild=0;
tree[i].rchild=0;
tree[i].data='0';
tree[i].weight=0.0;
}
for(i=0;i<n;i++)
{
getchar(); //getchar 吃掉回车
printf("请输入第%d个结点的字符和权重(空格隔开):\n",i);
scanf("%c %f",&ch,&f); //输入结点字符和权重
tree[i].data=ch;
tree[i].weight=f;
}
for(i=n;i<m;i++) //进行n-1次合并产生n-1个新结点
{
p1=0;p2=0; //预置最小次小权值的下标为0
small1=maxval; //预置最小次小权值为float型最大值
small2=maxval;
for(j=i-1;j>=0;j--) //循环找出最小、次小权值和下标
if(tree[j].parent==0)
if((tree[j].weight-small1)<0.0001) //float精度,当两者之差小于0.0001认为相等
{
small2=small1; //小于当前最小权值,更新最小权值和次小权值以及位置
small1=tree[j].weight;
p2=p1;
p1=j;
}
else
if((tree[j].weight-small2)<0.0001) //小于当前次小权值,更新次小权值和位置
{
small2=tree[j].weight;
p2=j;
}
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; //新生成结点权值为两小之和
}
OUTTREE(tree);
}
//哈夫曼编码
void HUFFMANCODE(codetype code[],hufmtree t[])
{
int i,j,c,p;
codetype cd; //定义缓冲变量
for(i=0;i<n;i++)
{
cd.start=n;
c=i; //从叶子节点出发线上回溯
p=tree[c].parent; //p指向c的双亲结点
cd.data=tree[c].data;
while(p!=0)
{
cd.start--;
if(tree[p].lchild==c) //判断是否是左孩子,是编码为‘0’cd.bits[cd.start]='0';
else //否则编码为‘1’
cd.bits[cd.start]='1';
c=p; //更新p的双亲结点,进行下一次循环
p=tree[c].parent;
}
code[i]=cd; //把一个字符的编码赋给相应code[i]
}
printf("输出每个字符的哈夫曼编码:\n"); //输出每个字符的哈弗曼编码
for(i=0;i<n;i++)
{
printf("%c: ",code[i].data);
for(j=code[i].start;j<n;j++)
printf("%c ",code[i].bits[j]);
printf("\n");
}
}
//哈夫曼译码
void HUFFMANDECODE(codetype code[],hufmtree t[])
{
int i,c=0;
char b[100]; //定义字符数组储存输入的字符串
int endflag='#'; //电文结束标志位#
i=m-1; //从根结点开始向下搜索printf("请输入电文:\n");
printf("注意:电文结束标志为#\n");
getchar();
gets(b);
while(b[c]!=endflag) //遍历输入的字符串
{
if(b[c]=='0') //编码为0 走向左孩子
i=tree[i].lchild;
else
i=tree[i].rchild; //编码为1 走向右孩子
if(tree[i].lchild==0) //结点为叶子结点
{
putchar(code[i].data); //输出译码值
i=m-1; //回到根结点
}
c++ ;
}
printf("\n");
if((tree[i].lchild!=0)&&(b[c]!='#')) //电文读完尚未到叶子结点
printf("输入的电文有错误!\n");
}
//打印哈夫曼树
void OUTTREE(hufmtree t[])
{
int i;
printf("\n\n");
printf("结点数据权重双亲左孩子右孩子\n");
for(i=0;i<m;i++)
{
printf("%d",i);
printf(" %c",tree[i].data);
printf(" %f",tree[i].weight);
printf(" %d",tree[i].parent);
printf(" %d",tree[i].lchild);
printf(" %d\n",tree[i].rchild);
}
}。

相关文档
最新文档