题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1053
题目大意:求输入的字符串的霍夫曼编码的编码效率。
题意分析:此题思路比较简单,基本原理就是大学数据结构中的霍夫曼编码的实现:把给每个字符在字符串中出现的次数作为该字符的权值,然后建立二叉树存储该字符,权值越小,在二叉树中的深度越深,权值越大,在二叉树中的深度越浅。方法就是:
1、每次选择所有字符串队列中权值最小的两个字符,然后建立一个新节点,将这两字符节点连接起来,新节点的权值为这两个字符节点的权值之和。
2、然后将新节点加入原队列中,再迭代进行上述操作,直到最后建成一棵树,即只剩一个节点。因为每次从队列中选择权值最小的节点,故采用优先队列比较合适。
3、得到的这棵树中,所有字符节点都在叶节点上,用叶节点的权值乘以该叶节点的深度(根节点的深度为0),即为该霍夫曼编码的编码长度。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
using namespace std;
int cmp(const void *a, const void *b)
{
return *(char*)a - *(char*)b;
}
class TreeNode
{
public:
char ch;
int count;
int depth;
TreeNode *leftChild, *rightChild;
TreeNode()
{
ch = '\0';
count = 0;
depth = 0;
leftChild = NULL;
rightChild = NULL;
}
friend bool operator<(const TreeNode &a, const TreeNode &b)
{
return a.count > b.count;
}
};
priority_queue<TreeNode> que;
queue<TreeNode> q;
int res;
void hoffman()
{
TreeNode *root, *a, *b, *c, newNode;
while(que.size() > 1){
a = new TreeNode;
*a = que.top();
que.pop();
b = new TreeNode;
*b = que.top();
que.pop();
c = new TreeNode;
c->count = a->count + b->count;
c->leftChild = a;
c->rightChild = b;
que.push(*c);
}
root = new TreeNode;
*root = que.top();
root->depth = 0;
que.pop();
q.push(*root);
while(!q.empty()){
newNode = q.front();
q.pop();
if(newNode.leftChild){
newNode.leftChild->depth = newNode.depth + 1;
q.push(*newNode.leftChild);
}
if(newNode.rightChild){
newNode.rightChild->depth = newNode.depth + 1;
q.push(*newNode.rightChild);
}
if(!newNode.leftChild && !newNode.rightChild){
res += newNode.depth * newNode.count;
}
}
}
int main()
{
int i, j, len, count;
char str[1005];
while(scanf("%s", str)!=EOF && strcmp("END", str)!=0){
len = strlen(str);
qsort(str, len, sizeof(char), cmp);
TreeNode t;
count = 1;
t.ch = str[0];
for(i=1; i<len; i++){ //将字符按出现次数插入优先队列
if(str[i-1] == str[i]){
count++;
}
else{
t.count = count;
que.push(t);
t.ch = str[i];
count = 1;
}
}
t.count = count;
que.push(t);
res = 0;
if(que.size() == 1){
printf("%d %d 8.0\n", 8*len, len);
que.pop();
}
else{
hoffman();
printf("%d %d %.1lf\n", 8*len, res, 8*len*1.0/res);
}
}
return 0;
}