POJ—Entropy
题目描述 英文
熵编码器是一种数据编码方法,其通过对去除了“浪费”或“额外”信息的消息进行编码来实现无损数据压缩。
考虑文本“AAAAABCD”。使用ASCII,编码需要64位。由于字形“A”以更高的频率出现,可以通过用更少的位编码来做得更好吗?最佳编码是将“A”编码为“0”,将“B”编码为“10”,将“C”编码为“110”,和“D”与“111”。(这显然不是唯一的最佳编码,因为很明显,对于任何给定的编码,B,C和D的编码可以自由地互换,而不会增加最终编码消息的大小。)使用此编码,消息编码为只有13位到“0000010110111”,压缩比为4.9:1(也就是说,最终编码消息中的每个位表示与原始编码中4.9位一样多的信息)。
输入
输入文件将包含一个文本字符串列表,每行一个。文本字符串将仅包含大写字母数字字符和下划线(用于代替空格)。输入的结尾将由仅包含单词“END”作为文本字符串的行发出信号。
输出
对于输入中的每个文本字符串,输出8位ASCII编码的位长度,最佳无前缀可变长度编码的位长度,以及精确到一个小数点的压缩率。
样例输入
AAAAABCD
THE_CAT_IN_THE_HAT
END
样例输出
64 13 4.9
144 51 2.8
解题思路
本题考察的主要内容为哈夫曼树
案例第一个输出表示字符串用ASCII存储所使用的位数,即 长度 * 8即可.第二个输出为使用二进制编码来存储字符,但要求位数最少,这时我们得使用哈夫曼编码了.我们在处理时只需要求出所给字符的哈夫曼编码的WPL即为最短字符编码.
第三个输出即为第一,第二的商.
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
int arr[50],total;
string str;
priority_queue<int,vector<int>,greater<int> > Q;
int main()
{
while(cin>>str&&str!="END"){
while(!Q.empty()){
Q.pop();
}
memset(arr,0,sizeof(arr));
total = 0;
for(int i = 0; i < str.size(); i++){
if(str[i]!='_'){
arr[str[i]-'A']++;
}else{
arr[26]++;
}
}
//cout<<"------------------"<<endl;
for(int i = 0; i <=26; i++){
if(arr[i]){
Q.push(arr[i]);
//cout<<arr[i]<<"\t";
}
}
//cout<<endl;
//cout<<"-----------------"<<endl;
while(Q.size() > 1){
int w1 = Q.top();
Q.pop();
int w2 = Q.top();
Q.pop();
Q.push(w1+w2);
total+=w1+w2;
}
printf("%d %d %.1lf\n",str.size()*8,total,str.size()*8.0/total);
}
return 0;
}
代码解析
在进行计算哈夫曼树的WPL时,要注意如果只有一个字符,那么长度就是1.当大于1个字符,则进行构建哈夫曼树.
心得收获
- 当遇到字符时我们将其映射为数字的处理方式: 如A==> arr[0]=arr[ str[i] – ‘A’ ] (当str[i]
== A), B==> arr[1]=arr[ str[i] – ‘B’ ] (当str[i] == B).- 在竞赛时对于输入输出最好用C语言的,效率更高.
- 优先队列的使用.
- 特殊情况的处理,如方法一需要考虑字符种类个数是否大于1,方法二则可不用考虑.