🎈 作者:Linux猿
🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C++、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊!
🎈 关注专栏: 数据结构和算法成神路【精讲】优质好文持续更新中……🚀🚀🚀
🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬
目录
一、题目描述
二、输入描述
三、输出描述
四、测试样例
五、解题思路
六、代码实现
七、时间复杂度
本文是针对【数据结构和算法】超详细,超多图解,赫夫曼树详解 中「实战演练」题目的讲解,下面来详细讲解 POJ Entropy。
一、题目描述
原文题目较长,这里总结如下:
熵编码器是一种数据编码方法,通过对删除了“浪费”或“额外”信息的消息进行编码来实现无损数据压缩。有两种编码方式:
(1)固定长度编码:用 ASCII 编码的英文文本具有高度的熵,因为所有字符都使用相同的位数(8位)进行编码。
(2)用「赫(哈)夫曼编码」形式编码。
例如:考虑文本“AAAAA BCD”。使用ASCII编码,需要64位(每个字符 8 位,8个字符,8 * 8 = 64)。哈夫曼编码为将“A”与“0”编码,将“B”与“10”编码,“C”与“110”编码,以及将“D”与“111”编码。那么,字符串 “AAAAABCD” 需要 13 位,编码为“0000010110111”。压缩比为 4.9 : 1。
二、输入描述
输入文件将包含文本字符串列表,每行一个。文本字符串将仅包含大写字母数字字符和下划线(用于代替空格)。
输入的结束将包含一行,该行仅包含单词 “END” 作为文本字符串,此行不处理。
三、输出描述
对于输入中的每个文本字符串,输出 8 位 ASCII 编码的位长度、最佳无前缀可变长度编码的位长以及精确到小数点一位的压缩比。
四、测试样例
输入:
AAAAABCD
THE_CAT_IN_THE_HAT
END
输出:
64 13 4.9
144 51 2.8
样例一:字符串 “AAAAABCD” 通过 8 位 ASCII 编码长度为 64 位 (8 * 8 = 64),最佳无前缀可变长度编码(哈夫曼编码)为 13 位,压缩比为 64/13 约等于 4.9。
样例二:字符串 “THE_CAT_IN_THE_HAT” 通过 8 位 ASCII 编码长度为 144 位 (18 * 8 = 144),最贱无前缀可变长度编码(哈夫曼编码)为 51 位,压缩比 144/51 = 2.8。
五、解题思路
本题是「赫(哈)夫曼编码」的简单应用,本题首先需要计算出 8 位 ASCII 编码需要的位数,需要位数 = 字符串长度 * 8。
然后,就是「赫(哈)夫曼树」的应用了,步骤如下所示:
(1)统计每个单词出现的频率,可以先排序一下,然后遍历一遍字符串统计;
(2)模拟「赫(哈)夫曼树」建立过程,统计编码需要的位数。
六、代码实现
代码实现如下所示。
#include<iostream>
#include<queue>
#include<string>
#include<iomanip>
#include<algorithm>
using namespace std;
int main()
{
string str;
// C++ 优先队列
priority_queue< int,vector<int>,greater<int> > Q;
while(cin>>str && str != "END") {
sort(str.begin(), str.end()); //排序后,相同字符相邻
//统计每个字符出现的频次,并放入优先队列
int num = 1;
int n = str.size();
for(int i = 0; i < n; ++i) {
if(str[i] != str[i + 1]) {
Q.push(num);
num = 1;
} else {
++num;
}
}
int ans = 0; // 用于保存哈夫曼编码总长度
// 处理只有一种字符的特殊情况
if(Q.size() == 1) ans = Q.top();
while(Q.size() > 1) {
// 模拟建立哈夫曼树,取出两个最小的
int a = Q.top();
Q.pop();
int b = Q.top();
Q.pop();
Q.push(a + b);
ans += (a + b);
}
Q.pop();
cout<<n*8<<" "<<ans<<" "<<fixed<<setprecision(1)<<n*8.0/ans<<endl;
}
return 0;
}
在 POJ 提交 AC 截图如下所示。
七、时间复杂度
时间复杂度:O(nlogn + mlogm)
其中,n 表示字符的个数,m 表示字符的种类,对所有字符串排序的时间复杂度为 O(nlogn),通过「优先队列」进行「赫(哈)夫曼编码」的时间复杂度为O(mlogm)。
🎈 感觉有帮助记得「一键三连」支持下哦!有问题可在评论区留言💬,感谢大家的一路支持!🤞猿哥将持续输出「优质文章」回馈大家!🤞🌹🌹🌹🌹🌹🌹🤞