霍夫曼编码

给定一个文本中出现的一组字符C,每个字符有其出现频率freq,想构造字符的最优二进制表示,即用来编码整个文本的二进制位最少

定长编码:每个字符用相同长度的二进制位数进行编码,则每个字符的长度n必须满足,2^n = |C|
变长编码:思想是赋予高频字符短码字,赋予低频字符长码字

编码过程相对简单,将表示每个字符的码字连接起来即可完成文件压缩
解码过程,如果采用的定长编码则直接解码,变长编码可能产生歧义比较麻烦;但又一种变长编码是无歧义的——前缀吗
    前缀码,即没有任何码字是其他码字的前缀所以编码文件的开始码字是无歧义的

文件的最优编码方案总是对应一棵满(full)二叉树,即每个非叶节点都有两个孩子节点【证明很简单,反正即可,假设一棵非满二叉树是最优编码方案,取其不拥有两个孩子节点的非叶节点,分情况,如果它没有孩子节点,则取以其兄弟节点为根的的树的叶子节点为其孩子节点,这种编码方案更优,因此矛盾;如果它有左孩子节点或者右孩子节点,则取其存在的孩子节点上的叶子节点作为另外一个孩子节点,这种编码方案更有,也矛盾,因此得证】

构造霍夫曼编码
    C是字符集合,有n个字符,出现频率分别为c.freq;算法自底向上的构造出对应最优编码的二叉树。
    从|C|个叶节点开始,执行|C|-1个“合并”操作创建出最终的二叉树
    使用一个以属性freq为关键字最小的最优优先队列Q,从而识别最低频率的两个字符将其合并;当合并两个字符时,得到的新节点的频率设置两者频率之和
HUFFMAN(C)
    n = |C|
    Q = C                                //Q是最小优先队列,假定使用最小二叉堆实现,则时间复杂度为O(n)
    for i = 1 to n-1                //自底向上提取频率最小的两个节点组成新的节点
        allocate a new node z
        z.left = x = EXTRACT-MIN(Q)
        z.right = y = EXTRACT-MIN(Q)
        z.freq = x.freq + y.freq
        INSERT(Q, z)
    return EXTRACT-MIN(Q)        //最后只剩下根节点

霍夫曼编码的思想并不难,也容易理解;较难的地方在于证明其正确性【满足贪心选择性质和最优子结构性质】和编程实现
贪心选择性质x和y是C中频率最低的两个字符,则存在C的一个最优前缀编码,x和y的码字长度相同,且只有最后一个二进制位不同
最优子结构性质x和y是C中频率最低的两个字符,C去掉字符x和y,加入一个新字符z得到C',z.freq = x.freq + y.freq;T'是C'的一个最优前缀码对应的编码树,则将T'中叶节点z替换为一个以x和y为孩子的内部结点,得到树T,T表示字母表C的一个最优前缀码
在这里证明第二个性质,基于第一个
    B(T)表示按T进行编码需要多少二进制位
    首先B(T) = B(T') + x.freq + y.freq(因为x和y的深度都比z多1)
    反证法:假设T对应的前缀码不是最优前缀码,T''才是,则B(T'') < B(T)
    由性质一,T''包含兄弟节点x和y,令T'''为T''中将x/y及他们的父结点替换为叶节点z得到的树,则
    B(T''') = B(T'') - x.freq - y.freq < B(T) - x.freq - y.freq = B(T')
    与T'是最优前缀码矛盾,因此得证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值