• 数据结构实验之二叉树六:哈夫曼编码


    数据结构实验之二叉树六:哈夫曼编码

    Time Limit: 1000 ms Memory Limit: 65536 KiB

    Problem Description

    字符的编码方式有多种,除了大家熟悉的ASCII编码,哈夫曼编码(Huffman Coding)也是一种编码方式,它是可变字长编码。该方法完全依据字符出现概率来构造出平均长度最短的编码,称之为最优编码。哈夫曼编码常被用于数据文件压缩中,其压缩率通常在20%~90%之间。你的任务是对从键盘输入的一个字符串求出它的ASCII编码长度和哈夫曼编码长度的比值。

    Input

    输入数据有多组,每组数据一行,表示要编码的字符串。

    Output

    对应字符的ASCII编码长度la,huffman编码长度lh和la/lh的值(保留一位小数),数据之间以空格间隔。

    Sample Input

    AAAAABCD
    THE_CAT_IN_THE_HAT

    Sample Output

    64 13 4.9
    144 51 2.8

    首先说一下哈夫曼编码

    设某信源产生有五种符号u1、u2、u3、u4和u5,对应概率P1=0.4,P2=0.1,P3=P4=0.2,P5=0.1。首先,将符号按照概率由大到小排队,如图所示。编码时,从最小概率的两个符号开始,可选其中一个支路为0,另一支路为1。这里,我们选上支路为0,下支路为1。再将已编码的两支路的概率合并,并重新排队。多次重复使用上述方法直至合并概率归一时为止。

    • 哈夫曼编码_百度百科
      说白了哈夫曼树就是离散数学中的最优二叉树。那么根据最优二叉树的建成方法来用代码实现就可以了。
      每次取最小的两个节点,合成一个新的节点,直到节点为一为止,一棵由m个带权节点的最优二叉树含有(2*m-1)个节点。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    /*这里用数组模拟二叉树来完成哈夫曼编码(三叉链表有点麻烦,挖个坑,有机会补上)*/
    /*w表示出现的次数,l左儿子的序号,r右儿子的序号,p父亲节点的序号*/
    struct tree
    {
        char data;
        int w,l,r,p;
    }s[100050*4];
    
    int INF = 1e9+7;/*等价于 int INF = 1000000007  相当于一个无穷大的数*/
    
    int main()
    {
        char ss[100050];
        int i,j,num,m,n,w1,w2,k1,k2,p,sum,f[100050];
        while(scanf("%s",ss)!=EOF)
        {
            memset(f,0,sizeof(f));
            n = strlen(ss);
            m = 0;
            /*输入并且统计每个字母出现的次数,即带权节点*/
            for(i=0;i<n;i++)
            {
                for(j=0;j<m;j++)
                {
                    if(s[j].data==ss[i])
                    {
                        s[j].w++;
                        break;
                    }
                }
                if(j==m)
                {
                    s[m].data = ss[i];
                    s[m].w = 1;
                    s[m].l = s[m].r = s[m].p = -1;
                    m++;
                }
            }
            /*把剩余的节点写出来*/
            for(i=m;i<2*m-1;i++)
            {
                /*记录两个最小权值*/
                w1 = w2 = INF;
                /*记录两个最小权值的编号*/
                k1 = k2 = -1;
                /*查询两个最小权值*/
                for(j=0;j<i;j++)
                {
                    if(f[j])
                        continue;
                    if(s[j].w<w1)
                    {
                        w2 = w1;
                        k2 = k1;
                        w1 = s[j].w;
                        k1 = j;
                    }
                    else if(s[j].w<w2)
                    {
                        w2 = s[j].w;
                        k2 = j;
                    }
                }
                f[k1] = f[k2] = 1;
                /*建立一个新的节点*/
                s[i].w = s[k1].w + s[k2].w;
                s[i].l = k1;
                s[i].r = k2;
                s[i].p = -1;
                s[k1].p = s[k2].p = i;
            }
            sum = 0;
            /*计算哈夫曼树的编码长度(带权节点的权值*路径长度)*/
            for(i=0;i<m;i++)
            {
                num = 0;
                p = s[i].p;
                while(p!=-1)
                {
                    num++;
                    p = s[p].p;
                }
                sum += num * s[i].w;
            }
            printf("%d %d %.1f
    ",n*8,sum,8.0*n/sum);
        }
        return 0;
    }
    
  • 相关阅读:
    [BJOI2019] 删数
    [HNOI2019] 校园旅行
    [ARC093D] Dark Horse
    rpn模块
    通俗易懂谈强化学习
    np.random.choice()的用法
    深度学习模型量化
    np.array中的[::1]的一点理解
    如何增加深度学习模型的泛化能力(L1/L2正则化,dropout,数据增强等等)
    深度学习中的网络剪枝(pruning)简介
  • 原文地址:https://www.cnblogs.com/luoxiaoyi/p/9848211.html
Copyright © 2020-2023  润新知