—————  第二天  —————

————————————

概念1:什么是路径?

在一棵树中,从一个结点到另一个结点所经过的所有结点,被我们称为两个结点之间的路径。

上面的二叉树当中,从根结点A到叶子结点H的路径,就是A,B,D,H

概念2:什么是路径长度?

在一棵树中,从一个结点到另一个结点所经过的“边”的数量,被我们称为两个结点之间的路径长度。

仍然用刚才的二叉树举例子,从根结点A到叶子结点H,共经过了3条边,因此路径长度是3

概念3:什么是 结点的带权路径长度?

树的每一个结点,都可以拥有自己的“权重”(Weight),权重在不同的算法当中可以起到不同的作用。

结点的带权路径长度,是指树的根结点到该结点的路径长度,和该结点权重的乘积。

假设结点H的权重是3,从根结点到结点H的路径长度也是3,因此结点H的带权路径长度是 3 X 3 = 9

概念4:什么是 树的带权路径长度?

在一棵树中,所有叶子结点的带权路径长度之和,被称为树的带权路径长度,也被简称为WPL

仍然以这颗二叉树为例,树的路径长度是 3X3 + 6X3 + 1X2 + 4X2 + 8X2 = 53

哈夫曼树是由麻省理工学院的哈夫曼博士于1952年发明,这到底是一颗什么样的树呢?

刚才我们学习了树的带权路径长度(WPL),而哈夫曼树(Huffman Tree)是在叶子结点和权重确定的情况下,带权路径长度最小的二叉树,也被称为最优二叉树。

举个例子,给定权重分别为1,3,4,6,8的叶子结点,我们应当构建怎样的二叉树,才能保证其带权路径长度最小?

原则上,我们应该让权重小的叶子结点远离树根,权重大的叶子结点靠近树根。

下图左侧的这棵树就是一颗哈夫曼树,它的WPL是46,小于之前例子当中的53:

需要注意的是,同样叶子结点所构成的哈夫曼树可能不止一颗,下面这几棵树都是哈夫曼树:

假设有6个叶子结点,权重依次是2,3,7,9,18,25,如何构建一颗哈夫曼树,也就是带权路径长度最小的树呢?

第一步:构建森林

我们把每一个叶子结点,都当做树一颗独立的树(只有根结点的树),这样就形成了一个森林:

在上图当中,右侧是叶子结点的森林,左侧是一个辅助队列,按照权值从小到大存储了所有叶子结点。至于辅助队列的作用,我们后续将会看到。

第二步:选择当前权值最小的两个结点,生成新的父结点

借助辅助队列,我们可以找到权值最小的结点2和3,并根据这两个结点生成一个新的父结点,父节点的权值是这两个结点权值之和:

第三步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列

也就是从队列中删除2和3,插入5,并且仍然保持队列的升序:

第四步:选择当前权值最小的两个结点,生成新的父结点

这是对第二步的重复操作。当前队列中权值最小的结点是5和7,生成新的父结点权值是5+7=12:

第五步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列

这是对第三步的重复操作,也就是从队列中删除5和7,插入12,并且仍然保持队列的升序:

第六步:选择当前权值最小的两个结点,生成新的父结点

这是对第二步的重复操作。当前队列中权值最小的结点是9和12,生成新的父结点权值是9+12=21:

第七步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列

这是对第三步的重复操作,也就是从队列中删除9和12,插入21,并且仍然保持队列的升序:

第八步:选择当前权值最小的两个结点,生成新的父结点

这是对第二步的重复操作。当前队列中权值最小的结点是18和21,生成新的父结点权值是18+21=39:

第九步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列

这是对第三步的重复操作,也就是从队列中删除18和21,插入39,并且仍然保持队列的升序:

第十步:选择当前权值最小的两个结点,生成新的父结点

这是对第二步的重复操作。当前队列中权值最小的结点是25和39,生成新的父结点权值是25+39=64:

第十一步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列

这是对第三步的重复操作,也就是从队列中删除25和39,插入64:

此时,队列中仅有一个结点,说明整个森林已经合并成了一颗树,而这棵树就是我们想要的哈夫曼树:

private Node root;
private Node[] nodes;
//构建哈夫曼树
public void createHuffman(int[] weights) {//优先队列,用于辅助构建哈夫曼树Queue<Node> nodeQueue = new PriorityQueue<>();nodes = new Node[weights.length];//构建森林,初始化nodes数组for(int i=0; i<weights.length; i++){nodes[i] = new Node(weights[i]);nodeQueue.add(nodes[i]);}//主循环,当结点队列只剩一个结点时结束while (nodeQueue.size() > 1) {//从结点队列选择权值最小的两个结点Node left = nodeQueue.poll();Node right = nodeQueue.poll();//创建新结点作为两结点的父节点Node parent = new Node(left.weight + right.weight, left, right);nodeQueue.add(parent);}root = nodeQueue.poll();
}
//按照前序遍历输出
public void output(Node head) {if(head == null){return;}System.out.println(head.weight);output(head.lChild);output(head.rChild);
}
public static class Node implements Comparable<Node>{int weight;Node lChild;Node rChild;public Node(int weight) {this.weight = weight;}public Node(int weight, Node lChild, Node rChild) {this.weight = weight;this.lChild = lChild;this.rChild = rChild;}@Overridepublic int compareTo(Node o) {return new Integer(this.weight).compareTo(new Integer(o.weight));}
}
public static void main(String[] args) {int[] weights = {2,3,7,9,18,25};HuffmanTree huffmanTree = new HuffmanTree();huffmanTree.createHuffman(weights);huffmanTree.output(huffmanTree.root);
}

在这段代码中,为了保证结点队列当中的结点始终按照权值升序排列,我们使用了优先队列PriorityQueue

与此同时,静态内部类Node需要实现比较接口,重写compareTo方法,以保证Node对象在进入队列时按照权值来比较。

—————END—————

往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习在线手册深度学习在线手册AI基础下载(pdf更新到25集)本站qq群1003271085,加入微信群请回复“加群”获取一折本站知识星球优惠券,请回复“知识星球”喜欢文章,点个在看

算法漫画:什么是 “哈夫曼树” ?相关推荐

  1. 【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码

    介绍 哈夫曼(Haffman)这种方法的基本思想如下: ①由给定的n个权值{W1,W2,-,Wn}构造n棵只有一个叶子结点的二叉树,从而得到一个二叉树的集合F={T1,T2,-,Tn}. ②在F中选取 ...

  2. 数据结构与算法之Huffman tree(赫夫曼树 / 霍夫曼树 / 哈夫曼树 / 最优二叉树)

    目录 赫夫曼树概述 定义 构造赫夫曼树步骤 代码实现 赫夫曼树概述 HuffmanTree因为翻译不同所以有其他的名字:赫夫曼树.霍夫曼树.哈夫曼树 赫夫曼树又称最优二叉树,是一种带权路径长度最短的二 ...

  3. 数据结构与算法(赫夫曼树,赫夫曼编码)

    赫夫曼树 基本介绍: (1)给定n个权值作为n给叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称哈夫曼树(HuffmanTree),还有的树翻译为霍夫 ...

  4. 数据结构与算法学习④(哈夫曼树 图 分治回溯和递归)

    数据结构与算法学习④(哈夫曼树 图 回溯和递归 数据结构与算法学习④ 1.哈夫曼树 1.1.相关概念 1.2.哈夫曼树的构建 1.3.哈夫曼编码 1.4.面试题 2.图 2.1.图的相关概念 2.2. ...

  5. 【Lua】哈夫曼树构造算法的分析与实现

    哈夫曼树构造算法分析 1.哈夫曼树中权重越大的叶子离根越近,采用贪心算法构造哈夫曼树,首先选中权重值小的叶子结点进行构造 2.步骤 构造森林全是根:根据n个给定结点的权重值{W1, W2-Wn}构成 ...

  6. 哈夫曼树以及哈夫曼算法

    目录 一.哈夫曼树的定义 二.哈夫曼树的特点 三.哈夫曼算法(构造哈夫曼树的方法) 四.哈夫曼树的构造过程 五.哈夫曼树构造算法的实现 一.哈夫曼树的定义 1.哈夫曼树:最优树即带权路径长度(WPL) ...

  7. 哈夫曼树的java实现_java实现哈夫曼树

    哈夫曼译码,就是将输入的译码还原成对应的字符. 抽象的算法描述:将建立哈夫曼树.实现哈夫曼编码.哈夫曼译码都定义成 子函数的的形式, 然后在主函数中调用它们...... 数据结构课程设计设计题目: 哈 ...

  8. 赫夫曼树建立c语言源程序编译结果详细解释,c语言构建哈夫曼树(附运行结果图)[本站推荐]...

    #include#include#include int m,s1,s2; typedef struct { unsigned int weight; unsigned int parent,lchi ...

  9. 蓝桥哈夫曼树C语言,实验四 哈夫曼树及哈夫曼编码

    实验目的## 掌握哈夫曼树的概念.哈夫曼编码及其应用. 掌握生成哈夫曼树的算法. 会用哈夫曼树对传输报文进行编码. 掌握二叉树的二叉链表存储方式及相应操作的实现. ##实验内容## 用哈夫曼编码进行通 ...

  10. 数据结构(六)霍夫曼树与编码

    1.算法流程 (1)构建霍夫曼树:自底向上 根据统计频率构建霍夫曼树: A.把所有的节点扔进排序队列queue中: B.从queue选择选择前面两个最小的元素a.b,把最小的树a作为左节点,把最小的b ...

最新文章

  1. 边缘计算 — 与 5G
  2. Leetcode84 柱状图中最大的矩形 详细的解法
  3. 【数据挖掘】神经网络 后向传播算法 ( 梯度下降过程 | 梯度方向说明 | 梯度下降原理 | 损失函数 | 损失函数求导 | 批量梯度下降法 | 随机梯度下降法 | 小批量梯度下降法 )
  4. JAVA总结之数组篇
  5. LSI系新军搅局,PCIe固态盘混战?
  6. 升降压斩波电路matlab,升降压直流斩波电路及matlab仿真.doc
  7. ASP.NET Core使用Jaeger实现分布式追踪
  8. Redis积分排行榜设计与实现第一篇
  9. lazarus的动态方法和虚拟方法
  10. QT添加MySQL驱动依赖
  11. U盘病毒 hypertrm.exe 修复
  12. c语言如何用气泡法编程最大 最小值,[c语言冒泡排序法]C语言冒泡排序法详解
  13. PPT转图片(Java)
  14. excel不能复制粘贴怎么回事
  15. K41H 老笔记本维修升级记
  16. 姜小白的Python日记Day7 文件的读写
  17. Bootstrap4表单验证(纯JavaScript方法)
  18. iOS H5原生WKWebView调起支付宝客户端支付方案
  19. Kevg靶机渗透实现 8080端口 8081端口 1322端口实现
  20. 启动容器后,即便映射了端口,使用docker ps 命令查看,ports列也是空

热门文章

  1. [blog摘要]Exploring and Decoding ETW Providers using Event Log Channels
  2. xml web service
  3. Studio右键选项中没有Git?
  4. ctags对部分目录生成tags
  5. MVC核心功能组件和简介
  6. FAST300M无线宽带路由器FW300R(从)桥接TPLINK路由器(主)
  7. flask+vue进阶
  8. ROS+Turtlebot3+RVIZ 显示机器人历史轨迹方法
  9. SLAM学习--2D激光SLAM--入门学习
  10. Java中 读-写 文件 BufferedReader BufferedWriter