哈夫曼编码问题
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。根据哈夫曼编码的原理,根据用户输入的一段文本,请编程实现的哈夫曼编码的编码与解码过程,并给出该段文本的编码结果与解码结果。
注意:1.测试文本可以预先存储在文件中
2.叶结点的权重直接从文本中统计得出
#include
#include
#include
#include
#define MAXVALUE 10000 //定义最大权值
#define MAXLEAF 30 //定义哈夫曼树中叶子结点个数
#define MAXNODE MAXLEAF*2-1 //定义哈夫曼总结点数
#define MAXSIZE 256
int n;
char str[MAXLEAF];
typedef struct
{
int weight;
int parent;
int rchild;
int lchild;
}HNodeType;
typedef struct
{
char data;
int weight;
}HDatatype;
typedef struct
{
HDatatype data[MAXSIZE];
int number;
}HNodeNum;
/*
找到各个字符的权重并排序
*/
void Find_Weight(HNodeNum ** pHn,char val[])
{
int i,j;
HDatatype t;
*pHn = (HNodeNum* )malloc(sizeof(HNodeNum));
(*pHn)->number = 0;
for(i=0;i
((*pHn)->data[i]).weight = 0;
}
for(i=0;val[i]!='\0';i++) //存放数据并计算各种字符的权重
{
for(j=0;j<(*pHn)->number;j++)
{
if(((*pHn)->data[j]).data == val[i])
{
((*pHn)->data[j]).weight ++;
break;
}
}
if(j>=(*pHn)->number)
{
((*pHn)->data[j]).data = val[i];
((*pHn)->data[j]).weight = 1;
(*pHn)->number ++;
}
}
//冒泡法排序
for(i=0;i<(*pHn)->number-1;i++)
{
for(j=0;j<(*pHn)->number-1-i;j++)
{
if(((*pHn)->data[j]).weight >((*pHn)->data[j+1]).weight)
{
t = (*pHn)->data[j];
(*pHn)->data[j] = (*pHn)->data[j+1];
(*pHn)->data[j+1] = t;
}
}
}
for(i = 0; i <(*pHn)->number; i++) //输出各种字符和其所对应的权重
{
printf("%c %d\n",((*pHn)->data[i]).data, ((*pHn)->data[i]).weight);
}
}
HNodeNum * HuffmanTree(HNodeType HuffNode[])
{
/*哈夫曼树的构造算法*/
int i, j, m1, m2, x1, x2;
HNodeNum * pHn = NULL;
printf("输入字符串:\n");
gets(str);
Find_Weight(&pHn, str);
n = pHn->number; //得到叶子结点个数
for(i = 0; i < 2 * n - 1; i++) //数组Huffman[]初始化
{
HuffNode[i].weight = 0;
HuffNode[i].parent = -1;
HuffNode[i].lchild = -1;
HuffNode[i].rchild = -1;
}
for(i = 0; i < n; i++) //把构造哈夫曼树的权重放到静态
{
HuffNode[i].weight = (pHn->data[i]).weight;
}
for(i = 0; i < n-1; i++)
{
m1 = m2 = MAXVALUE;
x1 = x2 = 0;
for(j = 0; j < n+i; j++)
{
if(HuffNode[j].weight < m1 && HuffNode[j].parent == -1)
{
m2 = m1;
x2 = x1;
m1 = HuffNode[j].weight;
x1 = j;
}
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;
}
return pHn;
}
/*
定义哈夫曼编码的长度
*/
#define MAXBIT 100 //定义哈夫曼编码的最大长度
#define MAXSTR 1000 //定义字符串转化为哈夫曼编码的最大长度
typedef struct
{
int bit[MAXBIT];
int start;
}HCodeType;
void HuffmanCode()
{
/*生成哈夫曼编码*/
HNodeType HuffNode[MAXNODE];
HCodeType HuffCode[MAXLEAF], cd;
int HuffStr[MAXSTR];
HNodeNum * pHn = NULL;
int i, j, k, c, p, l = 0;
pHn = HuffmanTree(HuffNode); //建立哈夫曼树
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 = cd.start - 1;
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;
}
for(i = 0; i < n; i++) //输出各种字符对应的哈夫曼编码
{
printf("%c--",(pHn->data[i]).data);
for(j = HuffCode[i].start + 1; j < n; j++)
{
printf("%d",HuffCode[i].bit[j]);
}
printf("\n");
}
printf("转码为:");
//把字符串转化为haffman编码
for(i = 0; str[i]!='\0'; i++)
{
for(j = 0; j < n; j++)
{
if(str[i] == (pHn->data[j]).data)
{
for(k = HuffCode[j].start + 1; k < n; k++)
{
HuffStr[l] = HuffCode[j].bit[k];
printf("%d",HuffStr[l]);
l++;
}
}
}
}
printf("\n");
//解码
printf("解码为:");
c = 2 * n - 2;
for(i = 0; i < l; i++)
{
if(HuffStr[i] == 0)
{
c = HuffNode[c].lchild;
}
if(HuffStr[i] == 1)
{
c = HuffNode[c].rchild;
}
if(HuffNode[c].lchild == -1 && HuffNode[c].rchild == -1)
{
printf("%c",(pHn->data[c]).data);
c = 2 * n - 2;
}
}
printf("\n");
}
int main()
{
HuffmanCode();
}