问题描述:
给定一个字符串(长度不超过100),求哈夫曼编码的最短长度
样例输入:
输入1:
abbcccdddd
输出1:
19
输入2:
we will we will r u
输出2:
50
思路:
本题如果真要用哈夫曼来建树,计算值会非常复杂。
首先要能够发现规律:哈夫曼树的编码长度等于各个叶节点权值与路径长度乘积之和,同时这个值等于非叶节点之和。
采用优先队列模拟哈夫曼树的建立。采用map记录字符与出现的次数,将每个字符的次数依次加入优先队列(数值小的在队头),每一次从队列中出队最小的两个,相加后再加入队列中。用ans记录每一次相加和temp值之和,当队列中剩下一个元素时,ans的值即为所求
知识点:
priority_queue 优先队列:
- priority_queue<int>q; 默认为数字(字典序)大的值在队首top,等价于priority_queue<int, vector<int>, less<int> >q;
- priority_queue<int, vector<int>, greater<int> >q; 表示数字(字典序)小的在队首
- 没有front、back函数,只有top用于读取队首元素
注意:
- map中查找元素用find,要仔细
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
const int maxn = 100;
string str;
map<char, int> mp;
priority_queue<int, vector<int>, greater<int> >q;
int main(){
getline(cin, str);
int len = str.length();
for(int i = 0; i < len; i++){
if(mp.find(str[i]) == mp.end()){
mp[str[i]] = 1;
}
else{
mp[str[i]]++;
}
}
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
q.push(it->second);
}
int ans = 0;
while(q.size() != 1){
int a, b, temp;
a = q.top();
q.pop();
b = q.top();
q.pop();
temp = a + b;
ans += temp;
q.push(temp);
}
cout << ans << endl;
return 0;
}