问题描述:
给定一个字符串(长度不超过100),求哈夫曼编码的最短长度
样例输入:
样例1:
输入:
abbcccdddd
输出:
19
样例2:
输入:
we will we will r u
输出:
50
思路:
直接建哈夫曼树,再对叶子节点进行编码(编码规则:左1右0),最后计算编码长度。这种方法比较麻烦,可以根据哈夫曼树的性质来进行简化。
规律:哈夫曼编码长度等于 叶子节点的权值 * 路径 之和。
所以使用哈希表来记录每个字符的出现次数作为字符的权值,使用优先队列来实现求WPL(带权路径长度)的过程。
优先队列:
priority_queue<typename> name ;默认为数字(字典序)大的排在前面,等价于priority_queue<int, vector<int>, less<int> >q;
同理还有priority_queue<int, vector<int>, greater<int> >q; 就是小的排在前面。greater理解为递增,less理解为递减。
函数有push(),top(),pop(),empty(),size()。
这里我们使用priority_queue<int, vector<int>, greater<int> >q;来存放字符的权值,模拟WPL的运算。
代码:
1.使用了自己设置的int hashTable[ ]来存放字符的权值。
#include <cstdio>
#include <string>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
priority_queue<int, vector<int>, greater<int> >q;
int hashTable[1000] = {0};
bool cmp(int a, int b){
return a > b;
}
int main(){
string str;
getline(cin, str);
int len = str.length();
for(int i = 0; i < len; i++){
hashTable[str[i]]++;
}
sort(hashTable, hashTable + 1000, cmp);
int count = 0;
for(int i = 0; i < len; i++){
if(hashTable[i] != 0){
count++;
}else break;
}
for(int i = 0; i < count; i++){
q.push(hashTable[i]);
}
int sum = 0;
while(q.size() > 1){
int a = q.top();
q.pop();
int b = q.top();
q.pop();
q.push(a + b);
sum += a + b;
}
printf("%d\n", sum);
return 0;
}
2.使用map<char,int> mp;
#include <string>
#include <iostream>
#include <queue>
#include <map>
#include <cstdio>
#include <cstring>
using namespace std;
priority_queue<int, vector<int>, greater<int> >q;
map<char, int>mp;
int main(){
string str;
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 sum = 0;
while(q.size() > 1){
int a = q.top();
q.pop();
int b = q.top();
q.pop();
q.push(a + b);
sum += a + b;
}
printf("%d\n", sum);
return 0;
}