数据结构——哈夫曼树深入浅出含图解(含C++代码实现)

数据结构与算法 专栏收录该内容
10 篇文章 0 订阅

前言

问题:将百分制的成绩变为五分制的成绩

if(score < 60) grade = 1;
else if(score < 70) grade = 2;
else if(socre < 80) grade = 3;
else if(socre < 90) grade = 4;
else grade = 5;

我们将其画为一颗判定树
在这里插入图片描述
如果我们学生的成绩绝大多数都是90,80,但是60分的很少,这颗判定树的效率就很低了。

如果考虑学生成绩的分布概率
在这里插入图片描述
按照上述的查找方法,查找效率为:
0.05 * 1 + 0.15 * 2 + 0.40 * 3 + 0.30 * 4 + 0.10 * 4 = 3.15

修改判定树
在这里插入图片描述

if(score < 80)
{
    if(score < 70)
    {
        if(score < 60) grade = 1;
        else grade = 2;
    }
    else = 3;
}
else
{
    if(score < 90) grade = 4;
    else grade = 5;
}

此时的效率就是
0.05 * 3 + 0.15 *3 + 0.4 * 2 + 0.3 * 2 + 0.1 *2 = 2.2

显然比之前的判定树要好
根据这个,给了我们一个启示

如何根据结点不同的查找频率构造更有效的搜索树?

这个就是哈夫曼树要解决的问题

哈夫曼树

带权路径长度(WPL):

设有n个叶子节点,每个叶子节点带有权值 W k W_k Wk,从根节点到每个叶节点的长度为 L k L_k Lk,则每个叶子节点的带权路径长度之和就是 ∑ k = 0 n W k ∗ L k \sum_{k=0}^nW_k*L_k k=0nWkLk

什么是哈夫曼树

哈夫曼树(Huffman Tree),又称最优二叉树,是一类带权路径长度最短的树。假设有n个权值{w1,w2,…,wn},如果构造一棵有n个叶子节点的二叉树,而这n个叶子节点的权值是{w1,w2,…,wn},则所构造出的带权路径长度最小的二叉树就被称为哈夫曼树。

举例

在这里插入图片描述
如图二叉树,
WPL = (5+6)* 4 + (2+4)* 3 + 3 * 2 + 1 * 1 = 69

哈夫曼树的特点

哈夫曼树的特点:

  • 没有度为1的结点 ;
  • n个叶子节点数的哈夫曼树,节点总数为2n-1
  • 哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树;

哈夫曼树构建

思路:

  1. 将权值从小打到进行排序
  2. 每次把权值最小的两棵二叉树合并,这颗二叉树的权值就是并在一起两棵二叉树权值的和

比如 [1,2,3,4,5]
在这里插入图片描述
先将最小的两个子树合并,合并后的权值为两子树权值之和
a = 1 + 2 = 3
在这里插入图片描述
再进行排序,将最小两数合并
b = a + 3 = 6
在这里插入图片描述
重复12操作
c = 4 + 5 > b
在这里插入图片描述
最后再进行合并
在这里插入图片描述
此时WPL =
(1+2)*3 + 3 * 2 + (4+5) * 2 = 33

代码实现哈夫曼树的构造

这里我运用了我另一篇博客数据结构——堆的基本操作(堆的建立、插入、删除等)详解的知识,这里我运用了最小堆的相关操作,某些函数有所不同,我就不列出了

struct HuffmanTree {
    int Weight;
    HuffmanTree* Left, * Right;
};

HuffmanTree* CreateHuffmanTree(HNode* H) { //此处的HNode为最小堆
    int i;
    HuffmanTree* T;
    H = CreateHeap(H->Size);               //先将H-Data按照权值调整成最小堆
    for (i = 1;i < H->Size;i++) {
        T = new HuffmanTree;
        T->Left = DeleteMin(H);            //从最小堆中删除一个节点,作为新T的左子结点
        T->Right = DeleteMin(H);           //从最小堆中删除一个节点,作为新T的右子结点 
        T->Weight = T->Left->Weight + T->Right->Weight;  //计算新权值 
        H = Insert(H, T);                  //*将新T插入最小堆*/   
    }
    T = DeleteMin(H);
    return T;
}

Ps:本人初学数据结构,若有出现错误,欢迎指出

  • 5
    点赞
  • 0
    评论
  • 5
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

chenyu-max

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值