这么大长段的英文看懂了也是很不容易。感谢这学期的密码学让我对entropy有了点印象,对理解题目起到了很大的帮助。
所以啊,书都不是白念的,课都不是白听的~
言归正传。先上题目链接
点击打开链接
这道题刚开始看的时候理解的一塌糊涂,因为上一次学哈夫曼大概是一年前的算法课了,再上一次是一年半前的数据结构,再上一次是两年前的离散数学,太久远了。
但是还好认真学过看着看着就想起来,哎,好像学过一个什么算法和这个差不多,咦,好像叫哈夫曼树!翻开算法教材,瞬间想起来了。
知道了原理,还是不会写,因为刚开始刷算法题嘛,肯定需要一个过程。上网搜搜答案,发现一个很重要的思想,就是树除了根以外所有节点权值的和就可以反映编码总长度,也是,每个节点都是之前所有子孙叶子节点权值的和,而每个叶子节点对应的元素对应编码长度又都是对应的树层数。想想很好理解。
还是那句话。虽然借鉴了网上的代码思想,但是程序都是自己写出来的。相信自己慢慢会变强的!
下面上代码~
#include<iostream>
#include<queue>
#include<string>
#include<map>
using namespace std;
int main(){
priority_queue<int,vector<int>,greater<int> > q;//优先队列,默认由大到小排序,这种写法可以改为由小到大排序
map<char,int>f;//字符对应频率建立映射
map<char,int>::iterator iter;
string s;
cin>>s;//
while(s!="END"){
for(int i=0;i<s.length();i++){
iter=f.find(s[i]);
if(iter==f.end()){
f[s[i]]=1;//初始化
}
else{
f[s[i]]++;//再次出现
}
}
iter=f.begin();
while(iter!=f.end()){//将次数对应写入map
q.push(iter->second);
iter++;
}
//queue<int>::iterator iter1=q.begin();queue不能遍历
int m,n,sum=0;
if(q.size()==1){//只有一个字母
sum=q.top();
}
while(q.size()>1){
m=q.top();q.pop();//pop没有返回值
n=q.top();q.pop();
q.push(m+n);//建立新的节点
sum+=(m+n);//累加的思路
}
q.pop();//清除队列
f.clear();//清除映射
printf("%d %d %.1f\n",s.length()*8,sum,(double)((double)(s.length()*8)/sum));//
cin>>s;
}
return 0;
}
遇到的问题及总结如下:
1.priority_queue 这个东西以前没有见过。
2.scanf是不能接收string的。
3.queue是不能遍历的。
4.queue的pop没有返回值。要访问只能先用top。
5.输入多组数据的情形一定要考虑到相关容器的清空,变量的初始化。
6.printf限制小数点的格式要注意,而且要注意数据类型的转换!尤其是除法!
加油加油~