复旦大学计算机学院上机考试——(2016-3) 字符串的哈夫曼编码长度

问题描述:

给定一个字符串(长度不超过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;
	 
	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值