如何建立一棵哈夫曼树并且输出压缩码

   如何建立一棵哈夫曼树并且输出压缩码

算法:1、给定一个具有n个权值{ w1,w2,………wn }的结点的集合 F = { T1,T2,………Tn } 2初始时,设集合 A = F 3执行 i = 1 n -1的循环,在每次循环时执行以下操作从当前集合中选取权值最小、次最小的两个结点,以这两个结点作为内部结点 bi的左右儿子,bi的权值为其左右儿子权值之和。在集合中去除这两个权值最小、次最小的结点,并将内部结点bI加入其中。这样,在集合A中,结点个数便减少了一个。这样,在经过了n-1次循环之后,集合A中只剩下了一个结点,这个结点就是根结点。

哈夫曼树的存储:在哈夫曼树中,每个要编码的元素是一个叶结点(度数为零),其它结点都是度数(度数就是有多少个子节点)为2的节点一旦给定了要编码的元素个数,由n0n21可知哈夫曼树的大小为2n-1哈夫曼树可以用一个大小为2n的数组来存储。0节点不用,根存放在节点1。叶结点依次放在n+12n的位置每个数组元素保存的信息:结点的数据、权值和父结点和左右孩子的位置。

代码实现:

//哈夫曼树及其编码,两个结构体,第一个是用来构造哈夫曼树的,第二个是用来保存压缩码的

#include<iostream>
using namespace std;
struct hfnode
{
    char data;//字符
    int weight;//字符的个数,也就是权值
    int parent,left,right;//父节点、左子树、右子树的数组下标
};
struct node
{
    char data;//字符
    char a[1000];//用于保存压缩码
    int num;//压缩码的长度
};
struct node *hftree(char str[],int d[],int size)
{
    int lenth=size*2,min1,min2,x,y,i,j;
    struct hfnode *hf;
    struct node *p;
    hf=(struct hfnode *)malloc(lenth*sizeof(struct hfnode));
    p=(struct node *)malloc(size*sizeof(struct node));
    for(i=size; i<lenth; i++) //size到(lenth-1)用来存放叶子节点
    {
        hf[i].data=str[i-size];
        hf[i].weight=d[i-size];
        hf[i].parent=hf[i].left=hf[i].right=0;
    }
    for(i=size-1; i>0; i--) //哈夫曼树的构造
    {
        min1=min2=100000000;
        x=y=0;//min1用来保存最小的,min2用来保存次小的
        for(j=i+1; j<lenth; j++)
        {
            if(min1>hf[j].weight&&hf[j].parent==0)
            {
                min2=min1;
                y=x;
                min1=hf[j].weight;
                x=j;
            }
            else if(min2>hf[j].weight&&hf[j].parent==0)
            {
                min2=hf[j].weight;
                y=j;
            }
        }
        if(x>y)
            swap(x,y);
        hf[i].weight=min1+min2;//新的节点的形成
        hf[i].parent=0;
        hf[i].left=x;
        hf[i].right=y;
        hf[x].parent=i;
        hf[y].parent=i;
    }
    for(i=size; i<lenth; i++) //求出各个字符的压缩码
    {
        int t1,t2;
        p[i-size].data=hf[i].data;
        p[i-size].num=0;
        t1=hf[i].parent;//父节点的数组下标
        t2=i;//自身的数组下标
        while(t1>0)
        {
            if(hf[t1].left==t2)
                p[i-size].a[p[i-size].num++]='0';
            else
                p[i-size].a[p[i-size].num++]='1';
            t2=t1;
            t1=hf[t1].parent;
        }
    }
    return p;
}
int main()
{
    char str[1000];
    int b[26],c[26],i,j,n,size;
    struct node *temp;
    while(scanf("%d",&n)!=EOF)//测试案例的个数
    {
        getchar();
        while(n--)
        {
            size=0;
            memset(b,0,sizeof(b));
            scanf("%s",str);
            for(i=0; str[i]!='\0'; i++)
                b[str[i]-'a']++;
            for(i=0; i<26; i++)
                if(b[i]!=0)
                {
                    c[size]=b[i];
                    str[size]=i+'a';
                    size++;
                }//c数组中保存的是各个字符的权值(也就是个数)
            temp=hftree(str,c,size);
            for(i=0; i<size; i++)
            {
                printf("%c:",temp[i].data);
                for(j=temp[i].num-1; j>=0; j--)
                    printf("%c",temp[i].a[j]);
                printf("\n");
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值