栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

哈夫曼树的求法,代码实现及证明,图文解释

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

哈夫曼树的求法,代码实现及证明,图文解释

哈夫曼树的定义
  • 路径和路径长度
    在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为 1,则从根结点到第 L 层结点的路径长度为 L−1。
  • 结点的权及带权路径长度
    若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
  • 树的带权路径长度
    树的带权路径长度规定为所有叶子结点(不是所有节点!)的带权路径长度之和,记为 WPL。

如上图的树的带权路径长度为7*3 + 2*2 + 5*1 = 30

我们知道给定任意叶节点,用不同方式构造出的二叉树,其带权路径长度往往不同,而哈夫曼树就是这些节点构造出的二叉树带权路径长度最小的情况

哈夫曼树的求法

如果初次接受这种解法可能觉得莫名其妙,后面会结合代码对求法给出解释,让你信服这种解法

哈夫曼树的构造采取的是一种贪心策略

  1. 将所有节点放入优先队列中。
  2. 提出最小的两个节点将其合并,它们的父节点权值为提取的两个节点权值之和,将它们的父节点重新放入优先队列,循环往复,知道只剩下一个节点
  3. 该节点即为所求的哈夫曼树

解法图示:

构造出这个树以后,如果要求最短树的带权路径长度,不仅可以直接用之前的方法,还可以直接求合并节点的权值和,即上面红色数字的和,即4+8+13=25。原理大家想一下应该就能明白,我就不多说了。这个计算方法不仅是代码的关键,也是之后证明的关键。

求最短树的带权路径长度代码实现

传送门:acwing 哈夫曼树
题目如下

#include
#include
using namespace std;

int main(){
    int n;
    int res = 0;//结果
    cin>>n;
    priority_queue, greater> q;
    while(n--){
        int num;
        cin>>num;
        q.push(num);
    }
    //当队列中只有一个节点就结束循环
    while(q.size()>1){
        int x = q.top();
        q.pop();
        int y = q.top();
        q.pop();
        int sum = x+y;//父节点权值
        q.push(sum);//将父节点放入优先队列中
        res += sum;//将合并的节点权值加到res中,就是上面我所说的“关键”
    }
    cout< 

如果是构建哈夫曼树的话把权值换成节点就可以了

求法的解释

其实如果你看懂为啥上面所有合并节点的权值之和就是最终结果,你应该就知道为什么可以这样做了。因为每次循环我都要加上一个合并出的节点权值,这个节点还要重新放入队列中等待下次合并,当然是从开始拿的越小越好。可能有些人看的可能有点蒙…hh,还是上面我说的,搞懂为啥所有合并节点的权值之和就是最终结果你就清楚了,如果实在搞不懂,这个方法记住就可以啦~

暑期编程PK赛 得CSDN机械键盘等精美礼品!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1017284.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号