数据结构--赫夫曼树

数据结构

–赫夫曼树

一.一些概念
  1. 路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。
  2. 路径长度:路径上的分支数目
  3. 树的路径长度:从树根到每个结点的路径长度之和

    路径长度为 = 1*2 + 2*3 + 3*1 = 11(第一个乘数表示层数)
  4. 结点的带权路径长度:从结点到树根之间的路径长度与结点上权的乘积
  5. 树的带权路径长度(WPL):树中所有叶子结点的带权路径长度之和

    WPL = 2*5 + 3*3 + 2*4 = 27(第一个乘数表示层数)
二.最优二叉树(赫夫曼树)

假设二叉树有n个叶子,其每个叶子结点带权wi,则带权路径长度WPL最小的二叉树称为最优二叉树或赫夫曼(Huffman)树。

三.赫夫曼树的构造
  1. 在赫夫曼树中,权值最大的结点离根最近,权值最小的结点离根最远。
  2. 算法:
    (1)根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F{T1, T2, …, Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,左右子树为空。
    (2)在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置其根结点的权值为其左右子树根结点的权值之和。
    (3)在F中删除这两棵树,同时将新得到的二叉树加入F中。
    (4)重复(2),(3),直到F只含一棵树为止。
    设已知权值W = {5, 6, 3, 9,7}, 求赫夫曼树。
四.赫夫曼编码

赫夫曼编码按各个字符出现的概率不同而给予不等长编码,可望减少编码总长度。
设给出一段报文:GOOD_GOOD_GOOD_GOOOOOOOO_OFF,字符集合是 { O, G, _, D, F},各个字符出现的频度(次数)是 W={ 15, 4, 4, 3, 2}。
(1)若给每个字符以等长编码:
  O: 000 G: 001 _: 010 D: 011 F: 100
则总编码长度为 (15+4+4+3+2) * 3 = 84

(2)若给每个字符以不等长编码(赫夫曼编码):
各字符{ O, G, _, D, F }出现概率为 { 15/28, 4/28, 4/28, 3/28, 2/28 }, 化整为{ 15, 4, 4, 3, 2 }
如果规定,Huffman树的左子树小于右子树,令左孩子分支为编码‘0’,右孩子分支为编码‘1’,则可构成Huffman树:


将根结点到叶子结点路径上的分支编码,组合起来,作为该字符的Huffman码,则可得到:
  O:1 _:011 G:010 D:001 F:000

则总编码长度为 15*1+(2+3+4+4)*3 = 54 < 84

  1. 编码实现
    (1)Huffman树的构造:
    n个叶子结点的Huffman树共2n-1个结点。(两两合并,直至一个,共生成n-1个结点)用静态链表实现, 结构如下。

    (2)算法:
    ----设静态链表为HT,计算过程如下:
    ① 初始令n=叶子结点数,设置0~n-1结点的data、weight,并令所有单元的parent,lchild,rchild为-1
    ② 从0~n-1中选取parent为-1,权值最小的两个结点,设为s1,s2,令n为此两结点的父结点,修改:
    HT[s1].parent = n; HT[s2].parent = n;
    HT[n].lchild = s1; HT[n].rchild = s2;
    HT[n].weight = HT[s1].weight+HT[s2].weight;
    HT[n].parent = -1;
    n++;
    ③ 重复②直至n=2*叶子结点数-1
    ----编码从叶子结点开始。对每个叶子结点k ,
    ① parent = HT[k].parent;
    若HT[parent].lchild = k; 则code=“0”+code;
    若HT[parent].rchild = k; 则code=“1”+code ;
    k = parent;
    ② 重复①直至HT[k].parent = -1;
    ③ 每个字符的编码值为string类对象code;
    ----用字符数组 char code[n]存放单结点编码。
  2. 解码实现
    (1)假设待解码字符串为s。
    思路:令k=树根,依次读s的每个字符,若为0,走k的左子树;
    为1,走k的右子树,直到走到叶结点,该节点即为得到的解码字符。
    重复上述过程,直到s串结束。
    若s串结束,k非树根,则解码失败。
    (2)算法:
    从树根开始,具体算法描述如下:
    ① 初始令k = 2n-2,i=0
    ② 若i>=s.length(),转⑥
    ③ 若s[i]=‘0’,则k = HT[k].lchild;否则,k=HT[k].rchild;
    ④ 若HT[k].lchild=-1且HT[k].rchild=-1,则解码串加HT[k].node, k=2n-2
    ⑤ i++,转②。
    ⑥ 若k=2n-2,解码正确,否则解码不正确。
五.前缀编码

若设计长短不等的编码,则必须是任一个字符的编码都不是另一个字符编码的前缀,称为前缀编码。
利用赫夫曼树可以构造一种不等长的二进制编码,并且构造所得的赫夫曼编码是一种最优前缀编码,即使所传电文的总长度最短。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X to Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值