目标功能:
从键盘接收一串电文字符,输出对应的编码,同时,能翻译由哈夫曼编码生成的代码串,输出对应的电文字符串。
- 构造一棵哈夫曼树;
- 输出哈夫曼树的中序遍历序列(字符及其权值);
- 实现哈夫曼编码,并用哈夫曼编码生成的代码串进行译码
原理分析:
首先,为了构造哈夫曼树,我们需要统计每个字符出现的频率,并将它们放入一个优先队列中,队列中的每个元素表示一个字符及其出现的频率。然后,我们可以通过取出队列中频率最小的两个元素,将它们组合成一个新节点,并将新节点放回优先队列。这个过程重复执行,直到队列中只剩下一个元素,即哈夫曼树的根节点。
接下来,我们可以使用中序遍历算法输出哈夫曼树的中序遍历序列,其中包括每个字符及其频率。
然后,我们就可以用哈夫曼编码生成代码串,哈夫曼编码的规则是将哈夫曼树中的每个节点标记为0或1,路径中左转为0,右转为1。对于每个字符,我们可以从根节点开始,按照哈夫曼编码规则找到对应的叶子节点,将该节点的路径上的0和1记录下来,这就是该字符的哈夫曼编码。
最后,我们可以用哈夫曼编码来翻译代码串,即根据哈夫曼编码规则,从根节点开始,依次将代码串中的0和1翻译为对应的字符,直到结束。
代码:
#include<stdio.h>
#include<conio.h>
#define MAXVALUE 10000 //定义最大权值
#define MAXLEAF 30 //定义哈夫曼树中叶子节点个数
#define MAXNODE MAXLEAF*2-1
#define MAXBIT 50
#define NULL 0
typedef struct node{
char letter;
int weight; //结点的权值
int parent; //结点的双亲
int lchild; //结点的左孩子
int rchild; //结点的右孩子
}HNodeType;
typedef struct{
char letter;
int bit[MAXBIT];
int start;
}HCodeType;
typedef struct{
char s;
int num;
}Message;
//哈夫曼树的构造算法
void HuffmanTree(HNodeType HuffNode[],int n,Message a[])
{
int i,j,m1,m2,x1,x2,temp1;char temp2;
for(i=0;i<2*n-1;i++) //HuffNode[]初始化
{
HuffNode[i].letter=NULL;
HuffNode[i].weight=0;
HuffNode[i].parent=-1;
HuffNode[i].lchild=-1;
HuffNode[i].rchild=-1;
}
for(i=0;i<n-1;i++)
for(j=i+1;j<n-1;j++)
if(a[j].num>a[i].num)
{
temp1=a[i].num;a[i].num=a[j].num;a[j].num=temp1;
temp2=a[i].s;a[i].s=a[j].s;a[j].s=temp2;
}
for(i=0;i<n;i++)
{
HuffNode[i].weight=a[i].num;
HuffNode[i].letter=a[i].s;
}
for(i=0;i<n-1;i++) //构造哈夫曼树
{
m1=m2=MAXVALUE;
x1=x2=0;
for(j=0;j<n+i;j++) //找出的两棵权值最小的子树
{
if(HuffNode[j].parent==-1&&HuffNode[j].weight<m1)
{
m2=m1;x2=x1;
m1=HuffNode[j].weight; x1=j;
}
else if(HuffNode[j].parent==-1&&HuffNode[j].weight<m2)
{
m2=HuffNode[j].weight;
x2=j;
}
}
//将找出的两棵子树合并为一棵子树
HuffNode[x1].parent=n+i;HuffNode[x2].parent=n+i;
HuffNode[n+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;
HuffNode[n+i].lchild=x1;HuffNode[n+i].rchild=x2;
}
}
//生成哈夫曼编码
void HuffmanCode(int n,Message a[])
{
HNodeType HuffNode[MAXNODE];
HCodeType HuffCode[MAXLEAF],cd;
int i,j,c,p;
char code[30],*m;
HuffmanTree(HuffNode,n,a); //建立哈夫曼树
for(i=0;i<n;i++)
{
cd.start=n-1;
c=i;
p=HuffNode[c].parent;
while(p!=-1) //由叶结点向上直到树根
{
if(HuffNode[p].lchild==c)
cd.bit[cd.start]=0;
else
cd.bit[cd.start]=1;
cd.start--;
c=p;
p=HuffNode[c].parent;
}
for(j=cd.start+1;j<n;j++) //保存求出的每个结点的哈夫曼编码和编码的起始位
HuffCode[i].bit[j]=cd.bit[j];
HuffCode[i].start=cd.start;
}
printf(" 输出每个叶子的哈夫曼编码:\n");
for(i=0;i<n;i++) //输出每个叶子结点的哈夫曼编码
{
HuffCode[i].letter=HuffNode[i].letter;
printf(" %c:",HuffCode[i].letter);
for(j=HuffCode[i].start+1;j<n;j++)
printf(" %d",HuffCode[i].bit[j]);
printf("\n");
}
printf(" 请输入电文(1/0):\n");
for(i=0;i<30;i++)code[i]=NULL;
scanf(" %s",&code); m=code;
c=2*n-2;
printf(" 输出哈夫曼译码:\n");
while(*m!=NULL)
{
if(*m=='0')
{
c=i=HuffNode[c].lchild;
if(HuffNode[c].lchild==-1&&HuffNode[c].rchild==-1)
{
printf("%c",HuffNode[i].letter);
c=2*n-2;
}
}
if(*m=='1')
{
c=i=HuffNode[c].rchild;
if(HuffNode[c].lchild==-1&&HuffNode[c].rchild==-1)
{ printf("%c",HuffNode[i].letter);
c=2*n-2;
}
}
m++;
}
printf("\n");
}
void main()
{
Message data[30];
char s[100],*p;
int i,count=0;
printf("\n 请输入一些字符:");
scanf("%s",&s);
for(i=0;i<30;i++)
{
data[i].s=NULL;
data[i].num=0;
}
p=s;
while(*p)
{
for(i=0;i<=count+1;i++)
{
if(data[i].s==NULL)
{
data[i].s=*p;data[i].num++;count++;break;
}
else if(data[i].s==*p)
{
data[i].num++;break;
}
}
p++;
}
printf("\n");
printf(" 不同的字符数:%d\n",count);
for(i=0;i<count;i++)
{ printf(" %c ",data[i].s);
printf(" 权值:%d",data[i].num);
printf("\n");
}
HuffmanCode(count,data);
getch();
}