题目:
假设某通信报文的字符集由A,B,C,D,E,F这6个字符组成,它们在报文中出现的频度(频度均为整数值)。 (1)构造一棵哈弗曼树,依次给出各字符编码结果。 (2)给字符串进行编码。 (3)给编码串进行译码。 规定: 构建哈弗曼树时:左子树根结点权值小于等于右子树根结点权值。 生成编码时:左分支标0,右分支标1。
输入:
第一行:依次输入6个整数,依次代表A,B,C,D,E,F的频度,用空格隔开。 第二行:待编码的字符串 第三行:待译码的编码串
输出:
前6行依次输出各个字符及其对应编码,格式为【字符:编码】(冒号均为英文符号) 第7行:编码串 第8行:译码串
输入样例:
3 4 10 8 6 5
BEE
0010000100111101
输出样例:
A:000
B:001
C:10
D:01
E:111
F:110
001111111
BADBED
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//定义哈夫曼树的 静态三叉链表结构
typedef struct
{
int Weight;
int Lchild, Rchild, Parent;
}HFNode;
typedef char * HFCode[7];
//在ht前i-1项中 选取双亲为0且权值最小的两结点s1,s2
void select(HFNode* hftree, int i, int * s1, int * s2)
{
int j, t, flag;
*s1 = *s2 = 0;
for(j = 1; j <= i; j++)
{
if(hftree[j].Parent == 0)
{
if(*s1 == 0)
*s1 = j;
else if(*s2 == 0)
{
*s2 = j;
flag = j;
break;
}
}
}
if(hftree[*s1].Weight > hftree[*s2].Weight)
{
t = *s1;
*s1 = *s2;
*s2 = t;
}
for(j = flag; j <= i; j++)
{
if(hftree[j].Parent == 0 && hftree[j].Weight < hftree[*s1].Weight )
{
*s2 = *s1;
*s1 = j;
}
else if(hftree[j].Parent == 0 && hftree[j].Weight < hftree[*s2].Weight )
{
*s2 = j;
}
}
}
//创建哈夫曼树
void CreateHuffman_Tree(HFNode* hftree)
{
int s1, s2;
for(int i = 1; i <= 6; i++)
scanf("%d",&hftree[i].Weight);
for(int i = 7; i < 12; i++)
{
select(hftree, i-1,&s1, &s2);
hftree[i].Weight = hftree[s1].Weight + hftree[s2].Weight;
hftree[i].Lchild = s1;
hftree[i].Rchild = s2;
hftree[s1].Parent = hftree[s2].Parent = i;
}
}
//哈夫曼编码
void HuffCode(HFNode* hftree, HFCode hfcode)
{
//由于题目中要求了 叶子结点个数为6 所以后面用的时候就不设置参数n 直接写成6了
int i, start, c, p;
//申请一块空间 用来临时存放结点的编码
char * temp = (char *)malloc(6 * sizeof(char));
temp[5]='\0';
for(i = 1; i <= 6; i++)
{
// strat=n-1 是因为 数组的前n个空间存放叶子结点 后面n-1个空间存放不断生成的子树
start = 5;
c = i;
p = hftree[c].Parent;
//在下面这个循环中 将下标为 i 的结点编码完成 并且存储在temp中
while(p != 0)
{
if(hftree[p].Lchild == c)
temp[--start] = '0';
else
temp[--start] = '1';
//编码是从最底下的结点开始找到根节点,所以每次循环结束都更新 p = hftree[c].Parent
c = p;
p = hftree[c].Parent;
}
//刚开始start=n-1 上面的循环每追溯一层 start--,所以此时 n-start 就是 这个结点的哈夫曼编码所需要的的空间
hfcode[i] = (char *)malloc((6-start) * sizeof(char));
strcpy(hfcode[i], &temp[start]);
}
//free掉 用来临时存放编码的temp
free(temp);
}
//输出编码
void PrintCode(HFNode* hftree, HFCode hfcode)
{
int i;
char x = 'A';
for(i = 1; i <= 6; i++)
printf("%c:%s\n",x+i-1, hfcode[i]);
}
//输出译码
void TransCode(HFCode hfcode, char * inputChar)
{
int i, index;
for(i = 0; i < strlen(inputChar); i++)
{
index = inputChar[i] - 'A' + 1;
printf("%s",hfcode[index]);
}
printf("\n");
}
//进行译码
void TransChar(HFNode* hftree, HFCode hfcode, char * inputCode)
{
//由于题目中要求了 叶子结点个数为6 所以后面用的时候就不设置参数n 直接写成6了
//p=11 是因为 一共需要2n-1个空间 并且该数组最后一个空间放的 就是最终哈弗曼树的 根节点!
int i = 0, j, p = 11, start;
//temp临时存储
char * temp = (char *)malloc(6 * sizeof(char));
while(inputCode[i] != '\0')
{
//初始化p为哈夫曼树根节点 的下标
p = 11;
start = 0;
while(1)
{
//循环对下标 p 的结点进行译码
if(hftree[p].Lchild != 0)
{
if(inputCode[i] == '0')
{
p = hftree[p].Lchild;
temp[start++] = '0';
}
else
{
p = hftree[p].Rchild;
temp[start++] = '1';
}
}
else
{
break;
}
i++;
}
temp[start] = '\0';
for(j = 1; j <= 6; j++)
{
if(strcmp(hfcode[j], temp) == 0)
{
printf("%c",'A'+j-1);
break;
}
}
}
free(temp);
}
int main()
{
char inputChar[100];
char inputCode[100];
HFNode hftree[12]={
0};
HFCode hfcode;
CreateHuffman_Tree(hftree);
HuffCode(hftree, hfcode);
scanf("%s",inputChar);
scanf("%s",inputCode);
PrintCode(hftree, hfcode);
TransCode(hfcode, inputChar);
TransChar(hftree, hfcode, inputCode);
return 0;
}