输入一个字符串(只能包含小写字母),建立哈夫曼树,并输出每个字符母的编码和总字符串的编码,以及熵和平均编码长度。
注意:字符串不能只含一种字母。
思路见注释。
#include<cstdio>
#include<queue>
#include<stdlib.h>
#include<string>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int cnt[26]={0},len=0,visit[26]={0};
const char buf[]="abcdefghijklmnopqrstuvwxyz";
char buf1[26];//存放出现过的字母
int cnt1[26];//记录buf1中对应位置字母的次数
char source[205];
map<char,string>s;将字母映射为它的编码
string str="";
typedef struct TreeNode{
int val;
char ch;
TreeNode *left;
TreeNode *right;
TreeNode():ch(' '),left(NULL),right(NULL){}
};
struct cmp{
bool operator() (const struct TreeNode* a,const struct TreeNode* b){
return a->val>b->val;//出现次数多的字母的优先级低
}
};
int read_code(){
scanf("%s",source);
int n=strlen(source),j=0;
for(int i=0;i<n;i++){
cnt[source[i]-'a']++;
}
for(int i=0;i<n;i++){
if(cnt[source[i]-'a']&&!visit[source[i]-'a']){
buf1[j]=source[i];
cnt1[j]=cnt[source[i]-'a'];
visit[source[i]-'a']=1;
j++;
}
}
buf1[j]='\0';
len=j;//出现过的字符的种类个数,也就是buf1的长度
return n;
}
TreeNode* Build_Tree(){
priority_queue<struct TreeNode*,vector<struct TreeNode*>,cmp >pq;//用优先队列保存每一个节点
for(int i=0;i<len;i++){//初始化,所有叶节点左右儿子为空
TreeNode* T1=(TreeNode*)malloc(sizeof(struct TreeNode));
T1->val=cnt1[i];
T1->ch=buf1[i];
T1->left=NULL;
T1->right=NULL;
pq.push(T1);
}
TreeNode* T;
for(int i=1;i<len;i++){
T=(TreeNode*)malloc(sizeof(struct TreeNode));//新建根节点
T->left=pq.top();
pq.pop();
T->right=pq.top();
pq.pop();
T->val=T->left->val+T->right->val;
//T->ch=' ';
pq.push(T);
}
return T;
}
void seachTree(TreeNode* root,string str){
if(root->left==NULL&&root->right==NULL){
printf("%c=%d\n",root->ch,root->val);
s[root->ch]=str;//遍历到叶子节点就映射出编码
cout<<str<<endl;
return;
}
seachTree(root->left,str+'0');
seachTree(root->right,str+'1');
}
void Free(TreeNode* root){//释放空间
if(root->left)
Free(root->left);
if(root->right)
Free(root->right);
free(root);
}
int main(){
int n=read_code();
double count1=0;
double H=0;
double p=0;
TreeNode* root=Build_Tree();
cout<<buf1<<endl;
seachTree(root,"");
for(int i=0;i<n;i++){
cout<<s[source[i]];
}
printf("\n");
for(int i=0;i<len;i++){
count1+=s[buf1[i]].size()*(cnt[buf1[i]-'a']*1.0/n);//计算平均码长
H-=(cnt[buf1[i]-'a']*1.0/n)*log2(cnt[buf1[i]-'a']*1.0/n);//计算熵
}
printf("H=%f\n",H);//编码效率
printf("averagelen=%f\n",count1);
printf("p==%f\n",H/count1);
Free(root);
return 0;
}