swust.oj986: 哈夫曼译码

986: 哈夫曼译码
题目描述

通常要求根据给定的编码本对密文进行解码。现已给定相应字符的哈夫曼编码,要求根据编码对密文进行解码。(建立哈夫曼树以及编码、主函数等都已经给出,你只需要填写译码函数void ccode(haffnode hafftree[],int n)即可。

输入

根据哈夫曼树编码表,针对字符串做好的编码结果。

输出

对每一行需要解码的串,进行解码,并输出解码后的结果。

样例输入

000100011011101110

样例输出

aabcc

void ccode(haffnode hafftree[], int n)
{
    char in[1000] ; //输入的编码
    scanf("%s",&in);
    int m = 2 * n - 1;//二叉树节点数 
    int i = m - 1;
    char it;
    int z=strlen(in);
    for(int j=0;j<z;j++)
//    for (string::const_iterator it = in.begin(); it != in.end(); ++it)
    {
    	it=in[j];
        if (it == '0') //为0则找左节点
        {
            i = hafftree[i].leftchild;
        }
        else  //否则找右节点
        {
            i = hafftree[i].rightchild;
        }
        if (hafftree[i].leftchild == -1)    //如果等于-1就输出
        {
            cout << hafftree[i].ch;
            i = m - 1;
        }
    }
}

哈夫曼树**

定义:

哈夫曼树是一种最优二叉树。给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。 这个定义里面涉及到了几个陌生的概念,下面就是一颗哈夫曼树,我们来看图解答。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2b0FFuyQ-1591856815922)(https://github.com/wangkuiwu/datastructs_and_algorithm/blob/master/pictures/tree/huffman/01.jpg?raw=true)]

(01) 路径和路径长度

定义:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。 例子:100和80的路径长度是1,50和30的路径长度是2,20和10的路径长度是3。

(02) 结点的权及带权路径长度

定义:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。 例子:节点20的路径长度是3,它的带权路径长度= 路径长度 * 权 = 3 * 20 = 60。

(03) 树的带权路径长度

定义:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。 例子:示例中,树的WPL= 1100 + 2*50* + 320 + 3**10 = 100 + 100 + 60 + 30 = 290。

哈夫曼树的创建:

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,哈夫曼树的构造规则为:

1. 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点); 

2. 在森林中选出根结点的权值最小的两棵树进行合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和; 

3. 从森林中删除选取的两棵树,并将新树加入森林; 

4. 重复(02)、(03)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

以{5,6,7,8,15}为例,来构造一棵哈夫曼树。

img

第1步:创建森林,森林包括5棵树,这5棵树的权值分别是5,6,7,8,15。

第2步:在森林中,选择根节点权值最小的两棵树(5和6)来进行合并,将它们作为一颗新树的左右孩子(谁左谁右无关紧要,这里,我们选择较小的作为左孩子),并且新树的权值是左右孩子的权值之和。即,新树的权值是11。 然后,将"树5"和"树6"从森林中删除,并将新的树(树11)添加到森林中。

第3步:在森林中,选择根节点权值最小的两棵树(7和8)来进行合并。得到的新树的权值是15。 然后,将"树7"和"树8"从森林中删除,并将新的树(树15)添加到森林中。

第4步:在森林中,选择根节点权值最小的两棵树(11和15)来进行合并。得到的新树的权值是26。 然后,将"树11"和"树15"从森林中删除,并将新的树(树26)添加到森林中。

第5步:在森林中,选择根节点权值最小的两棵树(15和26)来进行合并。得到的新树的权值是41。 然后,将"树15"和"树26"从森林中删除,并将新的树(树41)添加到森林中。 此时,森林中只有一棵树(树41)。这棵树就是我们需要的哈夫曼树!

应用:

哈夫曼编码原理:

能否使编码总长度更短呢?

实际应用中各字符的出现频度不相同,用短(长)编码表示频率大(小)的字符,使得编码序列的总长度最小,使所需总空间量最少

数据的最小冗余编码问题

在上例中,若假设 A, B, C, D 的编码分别为 0,00,1,01,则电文 ‘ABACCDA’ 便为 ‘000011010’(共 9 位),但此编码存在多义性:可译为: ‘BBCCDA’、‘ABACCDA’、‘AAAACCACA’ 等。

译码的惟一性问题

要求任一字符的编码都不能是另一字符编码的前缀,这种编码称为前缀编码(其实是非前缀码)。 在编码过程要考虑两个问题,数据的最小冗余编码问题,译码的惟一性问题,利用最优二叉树可以很好地解决上述两个问题

用二叉树设计二进制前缀编码

以电文中的字符作为叶子结点构造二叉树。然后将二叉树中结点引向其左孩子的分支标 ‘0’,引向其右孩子的分支标 ‘1’; 每个字符的编码即为从根到每个叶子的路径上得到的 0, 1 序列。如此得到的即为二进制前缀编码。

img

编码: A:0, C:10,B:110,D:111 任意一个叶子结点都不可能在其它叶子结点的路径中。

文件的编码和解码

1、输入各字符和权值

2、构造哈夫曼树

3、进行哈夫曼编码

4、查找树,得到各个字符的哈夫曼编码

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值