一种huhffman树的写法

在这个代码里我规定了字符集是英文字母,输入是26行,每行代表一个字母的频数(从a~z);为了方便起见,在储存中我用小写英文字母表示。

(暂时只放代码,详解的话过阵子再补充由于对于一组字符集和频数对应的huffman编码会有好多种,所以这里给出一个我自己习惯的写法 

20:11开放完整代码,但是温馨提示,直接提交会wa。请仔细看注释。

 

/*
由于对于一组字符集和频数对应的huffman编码会有好多种,所以这里给出一个我自己习惯的写法 
*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;

struct node{        //用来存每个字符的频数和编码,以及字符本身 
    char n;int val;
    int a[100];int l;
    node() {n=0;memset(a,0,sizeof(a));l=0;val=0;}
    void print() {printf("%c ",n);for(int i=l;i>=1;i--) printf("%d",a[i]);puts("");}
    void add1(){a[++l]=1;return ;}//编码前补1 
    void add0(){a[++l]=0;return ;}//编码前补0 
}nd[100];

struct tree{        //用来构建小根堆 
    node ins[100];int len;
    int siz;
    tree() {memset(ins,0,sizeof(ins));len=0;siz=0x3f3f3f3f;}
    friend bool operator <(const tree &a,const tree &b) {return a.siz<b.siz;}//规定大小比较 
    friend bool operator >(const tree &a,const tree &b) {return a.siz>=b.siz;}
}t[100];
int qwq;

//手写小根堆 
tree q[100];int l;
void push(tree a) {
    q[++l]=a;int now=l;
    while(now>1) {
        int fa=now>>1;
        if(q[now]<q[fa]) {
            swap(q[fa],q[now]);
            now = fa;
        }
        else break;
    }
    return ;
}
bool empty() {return l==0;}
void pop() {
    swap(q[1],q[l]);l--;
    int now = 1;
    int ch1=now<<1;int ch2=now<<1|1;
    while(now<l){//每次都和左右儿子中较小的那个比较 
        if(q[ch1]<q[ch2]) {
            if(ch1>l) break;
            if(q[ch1]<q[now]) {
                swap(q[ch1],q[now]);
                now=ch1;
                ch1=now<<1;ch2=now<<1|1;
                continue ;
            }
            else break;
        }
        else {
            if(ch2>l) break;
            if(q[ch2]<q[now]) {
                swap(q[ch2],q[now]);
                now=ch2;
                ch1=now<<1;ch2=now<<1|1;
                continue ;
            }
            else break;            
        }
    }
}
tree top() {return q[1];}

tree modify(const tree &a,const tree &b) {//合并两个子树 
    tree c;                                            //定义先取出来的那一组在左子树,后取出来的那一组在右子树 
    c.siz=a.siz+b.siz;
    c.len=a.len+b.len;
    for(int i=1;i<=a.len;i++) {
        node book=a.ins[i];
        book.add0();                                //左子树补0 
        c.ins[i]=book;
    }
    for(int i=1;i<=b.len;i++) {
        node book=b.ins[i];
        book.add1();                                //右子树补1 
        c.ins[a.len+i]=book;        
    }
    return c;
}
tree qa,qb,qc;
int ans;
int main() {
//    freopen("2.txt","r",stdin);
//    freopen("final.txt","w",stdout);
    for(int i=0;i<26;i++) {
        scanf("%d",&qwq);                    //按照顺序读取a~z的频数 
        nd[i].n=char(i+'a');                //每个字符的初始情况 
        nd[i].val=qwq;                        //每个字符的频数 
        t[i].ins[++t[i].len]=nd[i];     //对每个字符建立节点 
        t[i].siz=qwq;
        push(t[i]);                            //存到小根堆里 
    }
    for(int i=1;i<=25;i++) {
        qa=top();pop();                    //每次取出两个最小的 
        qb=top();pop();
        ans=ans+qa.siz+qb.siz;            //统计wpl 
        qc=modify(qa,qb);                    //合并 
        push(qc);                            //将新的子树压进堆 
    }    
    printf("\nWPL=%d\n\n",ans);        //输出 
    for(int i=1;i<=qc.len;i++) {
        node book=qc.ins[i];
        book.print();
    }
    
}

 

posted @ 2023-03-30 12:30  米罗偕涯  阅读(293)  评论(2编辑  收藏  举报