1.问题描述
从键盘接收一串电文字符,输入对应的Huffman编码。同时,能翻译由Huffman编码生成的代码串,输出对应的电文字符串。
2.设计要求
1) 构造一棵 Huffman树。
2) 实现Huffman编码,并用Huffman编码生成的代码串进行译码。
3) 程序中字符和权值是可变的,实现程序的灵活性。
3.代码实现
参考文章:
http://blog.csdn.net/TW_345/article/details/50096819
http://blog.csdn.net/u010366748/article/details/50773903
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#define MAXBIT 100
#define MAXVALUE 10000
#define MAXLEAF 30
#define MAXNODE MAXLEAF*2 -1
typedef struct
{
int bit[MAXBIT];//存放 0或1 ,即根据左右顺序来进行编码
int start;//走过的次数
} HCodeType; /* 编码结构体 */
typedef struct
{
int weight;
int parent;
int lchild;
int rchild;
int value;
} HNodeType; /* 结点结构体 */
//构造一个哈夫曼树,n为叶子数
void createHuffmanTree(HNodeType HuffNode[MAXNODE],int n)
{
int i,j;//用于循环遍历
int m1,m2;//构造哈夫曼树中最小的两个结点的权值
int x1,x2;//构造哈夫曼树中最小的两个结点的序号
/*初始化存放哈夫曼树数组 HuffNode[] 中的节点*/
//如果有n个叶子,则总共有 2n-1 个结点
for(i=0;i<2*n-1;i++)
{
HuffNode[i].weight = 0;//权值
HuffNode[i].parent =-1;//等于-1表示无父结点,下面同
HuffNode[i].lchild =-1;
HuffNode[i].rchild =-1;
HuffNode[i].value=i; //实际值,可根据情况替换为字母
}
//给n个叶子结点赋权值
for(i=0;i<n;i++)
{
printf("请输入第%d个叶子的权值:",i);
scanf("%d",&HuffNode[i].weight);
}
/*构建哈夫曼树*/
for(i=0;i<n-1;i++)
{
m1=m2=MAXVALUE;//m1 m2存放两个无父结点且结点权值最小的两个结点
x1=x2=0;//x1 x2 存放对应的序号
for(j=0;j<n+i;j++)
{
//先不断循环if语句,直到m1取到最小值,且左边小右边大
if(HuffNode[j].weight<m1 && HuffNode[j].parent==-1)
{
m2=m1;
x2=x1;
m1=HuffNode[j].weight;
x1=j;
}
//m1取到最小值后,无论如何第一个if都不会成立,此时elseif开始运行
else if (HuffNode[j].weight < m2 && HuffNode[j].parent==-1)
{
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;
printf ("x1.weight and x2.weight in round %d: %d, %d\n", i+1, HuffNode[x1].weight, HuffNode[x2].weight); /* 用于测试 */
printf ("\n");
}
}
/*解码,string数组是要破解的编码;Buf[];n是叶子数*/
void decoding(char string[], HNodeType Buf[],int Num)
{
int i,tmp=0,code[1024];//i用于遍历
int m=2*Num-1;//m代表结点数
char *nump;
char num[1024];
//
for(i=0;i<strlen(string);i++)
{
if(string[i]=='0')
num[i]=0;
else
num[i]=1;
}
i=0;
nump=&num[0];//nump指向编码
while(nump<(&num[strlen(string)]))
{
tmp=m-1;
while((Buf[tmp].lchild!=-1)&&(Buf[tmp].rchild!=-1))
{
if(*nump==0)
{
tmp=Buf[tmp].lchild ;
}
else tmp=Buf[tmp].rchild;
nump++;
}
printf("%d",Buf[tmp].value);
}
}
int main()
{
HNodeType HuffNode[MAXNODE];//定义一个结构体数组
HCodeType HuffCode[MAXLEAF],cd;//存放一个编码结构体数组,同时定义个临时变量存放解码信息
int i, j, c, p, n;//i,j用于循环;c表示孩子结点,p代表父结点,n表示叶子数
char pp[100];
printf("请输入叶子数n:");
scanf("%d",&n);
createHuffmanTree(HuffNode,n);
/*开始进行编码*/
for(i=0;i<n;i++)
{
cd.start=n-1;//一条二叉树,最多不过n-1次路
c=i;//c指向0
p=HuffNode[c].parent;//p指向0的父结点
while(p!=-1)
{
/*cd用于临时存储编码,且由于从子结点向上逆推,故倒着存储*/
if(HuffNode[p].lchild==c)
cd.bit[cd.start]=0;//如果是左结点,就保存一个 0
else
cd.bit[cd.start]=1;//不然,就保存一个 1
cd.start--;//start往前推一位
c=p;//向上遍历,直到根结点
p=HuffNode[c].parent;
}
for(j=cd.start+1;j<n;j++)//因为在上面的while中,到了根结点后,start减了一下,故要+1
HuffCode[i].bit[j]=cd.bit[j];//保存编码
HuffCode[i].start=cd.start;//保存每个编码的起始位置
}
/*输出哈夫曼编码*/
for(i=0;i<n;i++)
{
printf("第%d个叶子的哈夫曼编码是:",i);
for(j=HuffCode[i].start+1;j<n;j++)
{
printf("%d",HuffCode[i].bit[j]);
}
printf(" start:%d",HuffCode[i].start);
printf("\n");
}
printf("请输入要破解的编码:");
scanf("%s",&pp);
decoding(pp,HuffNode,n);
getchar();
return 0;
}