【数据结构】哈夫曼树的建立、编码与译码(含完整代码)

概述

哈夫曼编码可以有效的压缩数据,通常可以节省20~90%的空间,具体压缩率依赖于数据的特性。我们将待压缩数据看作字符序列,根据每个字符出现的频率(也可以是字符对应的权重),通过哈夫曼贪心算法构造出字符的最优二进制表示。

这里我们只考虑前缀码,即没有任何码字是其他码字的前缀。前缀码可以保证达到最优的数据压缩率,且不会丧失一般性。但这里不做它做出证明。接下来我们介绍一下Huffman算法

算法设计思路

哈夫曼设计了一个贪心算法来构造最优前缀码,被称为Huffman code。它的正确性证明也依赖于贪心选择性质和最优子结构。

首先我们先设计一下存储结构,采用顺序表存储,开辟两个数组,一个用于存储Huffman树的结点,另一个用于存储Huffman树各个数据对应的前缀码,代码如下:

typedef struct huffman_Node //  结点
{
   
    char data;
    int weight;
    int parent, lchild, rchild;
} Node; 

typedef struct huffman_Code //  编码
{
   
    char data;
    string code;
} Code;
bool flag[N] = {
   false};//标志结点是否已经被加入树中
Node huff_tree[N];//Huffman树
Code huff_code[N];//前缀码数组
int n;//数据个数

接着我们根据输入的数据进行Huffman树的建树过程,这里我们采用顺序表结构进行存储,假设C是一个n个字符的集合,每个字符c∈C,c.weight对应它的出现频率(或者说是它的权重),然后先将n个字符存入Huffman树的数组中,其对应下标为0-n-1。接着,采用自底向上的构造出对应的最优编码的二叉树。从C中元素出发,进行|C|-1次合并操作创建出最终的二叉树。算法主要通过找到当前集合中出现频率(权重)最小的两个对象,将其合并,当合并两个对象时,得到的新对象的频率(权重)为原来两个对象的频率(权重)之和。
代码如下:

int find_min(int m)
    /**
     * @description: 该函数意在找到森林中未被找到过的
     * 且权值为最小的那颗树,采用顺序查找来搜索,最终
     * 返回它的下标
     * @param {*int m}
     * @return {*return id}
     */
    {
   
        int mi = INT_MAX, id = -1;
        for (int i = 0; i < m; ++i)
        {
   
            if (!flag[i] && huff_tree[i].weight < mi)
            {
   
                mi = huff_tree[i].weight;
                id = i;
            }
        }
        flag[id] = true;
        return id;
    }

    void build()
    /**
     * @description: 该函数为建立huffman树函数
     * 每次从森林中选取权值最小的两颗树,将其合并
     * 为一颗新树并加入森林中,然后将这两颗树删除
     * 显然每做一次操作减少一颗树,当进行了n-1次
     * 就可以得到最终形成的huffm树
     */
    {
   
        int i, cnt = 0;
        pr("请输入字符个数:\n");
        input(n);
        pr("请输入字符:    \n");
        for (i = 0; i < n; ++i)
        {
   
            cin >> huff_tree[i].data;
            huff_tree[i].weight = (int)huff_tree[i].data;
            huff_tree[i].lchild = huff_tree[i].rchild = -1;
        }
        //  左0右1  左小右大
        i = n;
        while (1)
        {
   
            if (cnt == n - 1)
            {
   
                int ii = find_min(i);
                huff_tree[ii].parent = -1;
                break;
            }
            int i1 = find_min(i);
            int i2 = find_min(i);

            h
  • 14
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
哈夫曼编码是一种用于数据压缩的方法,它基于字符出现频率来构建最优的编码表。下面是哈夫曼编码译码编码过程: 1. 哈夫曼编码: - 统计字符出现频率,并根据频率构建哈夫曼树。频率较高的字符位于树的较低层。 - 通过从根到叶子节点的路径上的0和1来表示字符,构建编码表。 - 使用编码表将输入文本中的字符替换为对应的哈夫曼编码。 2. 哈夫曼译码: - 使用相同的哈夫曼树编码表,读取编码后的二进制数据。 - 从根节点开始,按照读取到的0或1依次向左或向右移动,直到达到叶子节点。每次到达叶子节点后,输出对应的字符,并重新回到根节点继续读取。 下面是一个示例,展示如何使用哈夫曼编码译码来进行数据压缩和解压缩: 假设我们有以下文本:C知道 编程是很有趣的! 1. 统计字符频率并构建哈夫曼树: 字符频率:{空格: 4, C: 2, 知: 2, !: 1, 程: 1, 译: 1, 是: 1, 有: 1, 趣: 1, 的: 1, 编: 1, 码: 1} 构建的哈夫曼树如下: [11] / \ / \ / \ / \ / \ / \ / \ C 知 ␣ ! 程 译 \ \ / \ 是 有 \ \ \ / \ 趣 的 构建的编码表如下: C: 00 知: 01 ␣: 100 !: 1010 程: 1011 译: 1100 是: 11010 有: 11011 趣: 11100 的: 11110 编: 111110 码: 111111 2. 编码: 将输入文本中的字符替换为对应的哈夫曼编码,得到编码后的二进制数据:00 01 100 111110 1011 1100 11010 11011 11100! 3. 解码: 根据相同的哈夫曼树编码表,读取编码后的二进制数据进行译码,得到原始文本:C知道 编程是很有趣的!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值