05-树9 Huffman Codes(不建树)

原题链接

树(下)课后练习题3

解题思路

题目给了提示,不一定要每次都建立哈夫曼树,而是通过比较前缀码的长度是否为最优。

那么对于给定的一组字符和频率(因为输入输出字符都是按顺序的,所以没必要存这些字符),可以不建哈夫曼树的得到其WPL,主要是利用优先队列模拟小顶堆,只要优先队列中的元素个数大于1,就从中取出最小的两个元素,WPL加上这两个元素的和,然后再将这两个元素的和入队。

为什么是这样的?来自于合并果子问题。
在这里插入图片描述
在这里插入图片描述

如何判断一个同学的结果是否正确有两个地方:

  1. 判断其编码的wpl是否等于最优WPL
    得到WPL后,针对每个同学的结果,在输入时,记录下来编码(为了判断是否是前缀码,无二义性的),然后计算该同学编码结果的wpl,wpl每次都加上频率*编码长度。

  2. 判断这些编码是否是无二义性的前缀码
    将编码按字符串长度从小到大排序,然后依次看每一个编码是否是后面编码的一部分即可

源代码

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100;
priority_queue<int, vector<int>, greater<int> > q;//优先队列替代小顶堆
int data[maxn];//存放各个元素的频率 
string prefix[maxn];//存放各个前缀 
int n, WPL = 0; 
bool cmp(string s1, string s2){
	return s1.length() < s2.length();
}
bool check(){
	char ch;
	int wpl = 0;
	bool flag = true;//答案是否正确 
	for(int i=0; i<n; i++){
		cin>>ch;
		cin>>prefix[i];
		wpl += data[i]*prefix[i].length();
	}
	if(wpl != WPL)
		flag = false;
	//下面继续判断是否为前缀码
	//按长度排序
	sort(prefix, prefix+n, cmp); 
	for(int i=0; i<n-1; i++){
		for(int j=i+1; j<n; j++){
			if(prefix[i] == prefix[j].substr(0, prefix[i].length())){
				flag = false;
				break;
			}
		} 
	}
	return flag;	 
}
int main(){
	int m;
	cin>>n;
	getchar();
	char ch;
	for(int i=0; i<n; i++){
		cin>>ch;
		cin>>data[i];
		getchar();
		q.push(data[i]);
	}
	//求出正确的WPL 
	while(q.size() > 1){
		int top1 = q.top();
		q.pop();
		int top2 = q.top();
		q.pop();
		WPL += (top1+top2);
		q.push(top1+top2); 
	}
//	printf("%d\n", WPL);
	cin>>m;
	for(int i=0; i<m; i++){
		if(check())//WPL是最短且是前缀码 
			cout<<"Yes"<<endl;
		else
			cout<<"No"<<endl; 
	}
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章