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

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

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;
}
原文地址:https://www.cnblogs.com/luoxiaoyi/p/9848211.html