题目的链接为:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1022
题目的描述为:
哈夫曼编码与
译码
时间
限制(普通/Java):1000MS/3000MS 运行
内存限制:65536KByte
总提交:343 测试通过:123
描述
已知电文包括的字符集为{A,C,I,M,N,P,T,U},输入对应权值,对字符集合进行哈夫曼编码,完成电文的哈夫曼编码与译码工作。
输入
共三行:
第一行为对应字符集{A,C,I,M,N,P,T,U}的权值
第二行为一段字符串表示的电文(长度不超过1000);
第三行为一段电文的哈夫曼编码。
输出
共十行:
前八行为各字符的编码;
第九行是与第二行输入对应的哈夫曼编码;
第十行是与第三行输入对应的电文。
样例输入
1 2 3 4 5 6 7 8
NUPTICPCACM
1111011111100
样例输出
A: 11110
C: 11111
I: 1110
M: 100
N: 101
P: 110
T: 00
U: 01
1010111000111011111110111111111011111100
ACM
哈弗曼编码,是一种很常用的压缩数据的方式。它将频率出现得高的用短编码,频率出现得低的字母用长编码。对哈夫曼编码的
理解,就是对压缩的理解。
如对于A,C,I,M,N,P,T,U
他们出现的频率为1,2,3,4,5,6,7,8
首先将他们全都变为单个的树节点,然后将权重小的组成树,即选择1,2组成树,这个树的权重为3,左子树为1,右子树为2,将新的树放入集合。
3(1,2),3,4,5,6,7,8
最小的是权重为3的两颗树,将其合并为新的树,并放入集合:
4,5,6,6(3(1,2),3),7,8
依次类推,就可以建立一颗哈弗曼树。哈夫曼树从节点到左子树根节点为0,到右子树根节点为1。按照这个规则,我们可以根据从根节点到叶子节点的路径,得知叶子节点所代表的字母的编码。译码即
逆向思维。
其实对树比较熟悉的话,这道题比较容易就能够做出来。
代码如下:
#include<iostream>
#include<algorithm>
#include<string>
#define MAXNUM 1001
using namespace std;
//哈夫曼树的节点
typedef struct node{
//树节点的标志
char data;
//树节点的权重
int weight;
//左右孩子
int lchild;
int rchild;
//是否已经被放入树中
bool tag;
}myNode;
bool compare(myNode mynode1,myNode mynode2)
{
return mynode1.weight<mynode2.weight;
}
myNode nodes[100];
char mycode[100];
char ch[]={'A','C','I','M','N','P','T','U'};
int index=-1;
int index1=-1;
//记录每个字母的哈弗曼编码
string str[8];
myNode recordNode;
bool judge()
{
int record=0;
for(int i=0;i<=index;i++)
{
if(nodes[i].tag==false)
{
record++;
recordNode=nodes[i];
}
}
if(record==0||(record==1&&recordNode.data=='#'))
{
return true;
}
return false;
}
int findNode()
{
for(int i=0;i<=index;i++)
{
if(nodes[i].tag==false)
{
nodes[i].tag=true;
return i;
}
}
return -1;
}
//编码
bool code(myNode *root,char ch1)
{
bool tag=false;
if(root->data==ch1)
{
return true;
}
int arr[2];
arr[0]=root->lchild;
arr[1]=root->rchild;
for(int i=0;i<2;i++)
{
if(arr[i]!=-1)
{
tag=code(&nodes[arr[i]],ch1);
if(tag)
{
if(i==0)
{
mycode[++index1]='0';
}
else if(i==1)
{
mycode[++index1]='1';
}
}
if(tag)
{
return tag;
}
}
}
return tag;
}
//创建哈弗曼树
void createTree()
{
while(!judge())
{
//按照权重由小到大排序
sort(nodes,nodes+index+1,compare);
myNode newNode;
newNode.data='#';
newNode.lchild=findNode();
newNode.rchild=findNode();
newNode.weight=nodes[newNode.lchild].weight+nodes[newNode.rchild].weight;
newNode.tag=false;
nodes[++index]=newNode;
}
}
//输出字母对应的编码
void outputCode(char cha)
{
for(int i=0;i<8;i++)
{
if(cha==ch[i])
{
cout<<str[i];
break;
}
}
}
//译码
void decode1(string inputstr)
{
int kkindex=-1;
int len=inputstr.length();
while(kkindex<len)
{
bool find=false;
myNode tempNode=nodes[index];
char ch;
while(!find&&kkindex<len)
{
++kkindex;
if(inputstr[kkindex]=='0')
{
tempNode=nodes[tempNode.lchild];
}
else
{
tempNode=nodes[tempNode.rchild];
}
ch=tempNode.data;
if(ch!='#')
{
find=true;
}
}
if(ch!='#')
{
cout<<ch;
}
}
}
void input()
{
for(int i=0;i<8;i++)
{
int data;
cin>>data;
nodes[++index].data=ch[i];
nodes[index].weight=data;
nodes[index].lchild=-1;
nodes[index].rchild=-1;
nodes[index].tag=false;
}
//构造哈夫曼树
createTree();
//recordNode故为树的根
for(int i=0;i<8;i++)
{
index1=-1;
code(&(nodes[index]),ch[i]);
str[i]="";
for(int j=index1;j>=0;j--)
{
str[i]+=mycode[j];
}
}
//输出
for(int i=0;i<8;i++)
{
cout<<ch[i]<<": ";
cout<<str[i]<<endl;
}
//获得输入的字符串
string inputstr;
cin>>inputstr;
for(int i=0;i<inputstr.length();i++)
{
outputCode(inputstr[i]);
}
cout<<endl;
//输出译码结果
cin>>inputstr;
decode1(inputstr);
cout<<endl;
}
int main()
{
input();
system("pause");
return 0;
}