哈夫曼编码

输入一个字符串(只能包含小写字母),建立哈夫曼树,并输出每个字符母的编码和总字符串的编码,以及熵和平均编码长度。

注意:字符串不能只含一种字母。

思路见注释。

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值