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

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

Hint
Source

xam

思路:使用静态链表组织数据

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct node
{
    char data; // 数据
    int w, l, r, p; // w为权重,l为左孩子,r为右孩子,p为父节点
} tree[100];

int INF = 1e9+7; // 设置最大值

int main()
{
    char str[100];
    int i, j, num, n, m, w1, w2, k1, k2, p, sum, f[100]while(~scanf("%s", str))
    {
        memset(f, 0, sizeof(f)); // 初始化用来检查的f数组
        n = strlen(str);
        m = 0;
        for (i = 0; i < n; i++) // 遍历字符串
        {
            for (j = 0; j < m; j++)
            {
                if (tree[j].data == str[i]) // 若在已初始化的结点中存在该字符,则该节点权值+1
                {
                    tree[j].w++;
                    break;
                }
            }
            if (j == m) // 若已初始化的结点中不存在该字符,则生成一个新的结点
            {
                tree[m].data = str[i];
                tree[m].w = 1;
                tree[m].l = tree[m].r = tree[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 (tree[j].w < w1) // 选择两个权值最小的结点,其中w1比w2小
                {
                    w2 = w1;
                    k2 = k1;
                    w1 = tree[j].w;
                    k1 = j;
                }
                else if (tree[j].w < w2)
                {
                    w2 = tree[j].w;
                    k2 = j;
                }
            }
            // 找到权值最小的两个结点
            f[k1] = f[k2] = 1; // 标记已使用
            // 创建新的结点
            tree[i].w = tree[k1].w + tree[k2].w;
            tree[i].l = k1;
            tree[i].r = k2;
            tree[i].p = -1;
            // 连接三个结点
            tree[k1].p = tree[k2].p = i;
        }
        // 计算
        sum = 0;
        for (i = 0; i < m; i++)
        {
            num = 0;
            p = tree[i].p;
            while(p != -1)
            {
                num++;
                p = tree[p].p;
            }
            sum += num*tree[i].w;
        }
        printf("%d %d %.1f\n", n*8, sum, n*8.0/sum);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值