【数据结构(十·树结构的实际应用)】赫夫曼树(2)

2023-12-10 17:28

本文主要是介绍【数据结构(十·树结构的实际应用)】赫夫曼树(2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1. 基本介绍
  • 2. 赫夫曼树的创建
    • 2.1. 思路分析
    • 2.2. 代码实现


1. 基本介绍

  1. 给定 n 个权值作为 n 个叶子结点,构造一棵二叉树,若该树的 带权路径长度(wpl) 达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree), 还有的书翻译为霍(赫)夫曼树
  2. 赫夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

几个重要的概念:
    ① 路径路径长度:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为 1,则从根结点到第 L 层结点的路径长度为 L-1。
    ② 结点的权带权路径长度:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
    ③ 树的带权路径长度:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为 WPL(weighted path length) ,权值越大的结点离根结点越近的二叉树才是最优二叉树。

WPL 最小的就是赫夫曼树
    在这里插入图片描述

2. 赫夫曼树的创建

问题:
    给一个数列 {13, 7, 8, 3, 29, 6, 1},要求转成一颗赫夫曼树.

2.1. 思路分析

    ① 从小到大进行排序, 将每一个数据,每个数据都是一个节点 , 每个节点可以看成是一颗最简单的二叉树
    ② 取出根节点权值最小的两颗二叉树
    ③ 组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和
    ④ 再将这颗新的二叉树,以根节点的权值大小 再次排序, 不断重复 1-2-3-4 的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树

图解:

① 从小到大进行排序{1, 3, 6, 7, 8, 13, 29}, 将每一个数据,每个数据都是一个节点 , 每个节点可以看成是一颗最简单的二叉树
在这里插入图片描述

② 取出根节点权值最小的两颗二叉树,即1和3
在这里插入图片描述

③ 组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和(1+3=4)

在这里插入图片描述

④ 再将上面这颗新的二叉树,以根节点的权值大小 再次排序:取出上面 以根节点为4和6的二叉树,重复③步骤

在这里插入图片描述

⑤ 不断重复上述操作,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树
    (1)重复第一次

在这里插入图片描述

    (2)重复第二次

在这里插入图片描述

    (3)重复第三次

在这里插入图片描述

    (4)重复第四次(完成)

在这里插入图片描述

2.2. 代码实现

package huffmantree;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class HuffmanTree {public static void main(String[] args) {// TODO Auto-generated method stubint arr[] = { 13, 7, 8, 3, 29, 6, 1 };Node root = createHuffmanTree(arr);// 测试preOrder(root);//}// 编写一个前序遍历的方法public static void preOrder(Node root) {if (root != null) {root.preOrder();} else {System.out.println("是空树,不能遍历~");}}// 创建赫夫曼树方法/*** * @param arr 需要创建成赫夫曼树的数组* @return 创建好后的赫夫曼树的root节点*/public static Node createHuffmanTree(int[] arr) {// 第一步:为了操作方便// 1. 遍历arr数组// 2. 将arr的每个元素构成一个Node// 3. 将Node放入到ArrayList中List<Node> nodes = new ArrayList<>();for (int value : arr) {nodes.add(new Node(value));}// 处理的过程是一个循环的过程while (nodes.size() > 1) {// 排序:从小到大Collections.sort(nodes);System.out.println("nodes = " + nodes);// 取出根节点权值最小的两个二叉树// 1. 取出权值最小的节点(二叉树)Node leftNode = nodes.get(0);// 2. 取出第二小的节点(二叉树)Node rightNode = nodes.get(1);// 3. 构建一个新的二叉树Node parent = new Node(leftNode.value + rightNode.value);parent.left = leftNode;parent.right = rightNode;// 4. 从ArrayList删除处理过的二叉树nodes.remove(leftNode);nodes.remove(rightNode);// 5. 将parent加入到nodesnodes.add(parent);}// 返回赫夫曼树的root节点return nodes.get(0);}}//创建节点类
//为了让Node对象持续排序Collections集合排序
//让Node实现Comparable接口
class Node implements Comparable<Node> {int value;// 节点权值Node left;// 指向左节点Node right;// 指向右节点// 写一个前序遍历public void preOrder() {System.out.println(this);if (this.left != null) {this.left.preOrder();}if (this.right != null) {this.right.preOrder();}}public Node(int value) {this.value = value;}@Overridepublic String toString() {return "Node [value=" + value + "]";}@Overridepublic int compareTo(Node o) {// TODO Auto-generated method stub// 表示从小到大排序return this.value - o.value;}}

运行结果:

在这里插入图片描述

这篇关于【数据结构(十·树结构的实际应用)】赫夫曼树(2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/477793

相关文章

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Java 枚举的基本使用方法及实际使用场景

《Java枚举的基本使用方法及实际使用场景》枚举是Java中一种特殊的类,用于定义一组固定的常量,枚举类型提供了更好的类型安全性和可读性,适用于需要定义一组有限且固定的值的场景,本文给大家介绍Jav... 目录一、什么是枚举?二、枚举的基本使用方法定义枚举三、实际使用场景代替常量状态机四、更多用法1.实现接

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

Python Flask 库及应用场景

《PythonFlask库及应用场景》Flask是Python生态中​轻量级且高度灵活的Web开发框架,基于WerkzeugWSGI工具库和Jinja2模板引擎构建,下面给大家介绍PythonFl... 目录一、Flask 库简介二、核心组件与架构三、常用函数与核心操作 ​1. 基础应用搭建​2. 路由与参

Spring Boot中的YML配置列表及应用小结

《SpringBoot中的YML配置列表及应用小结》在SpringBoot中使用YAML进行列表的配置不仅简洁明了,还能提高代码的可读性和可维护性,:本文主要介绍SpringBoot中的YML配... 目录YAML列表的基础语法在Spring Boot中的应用从YAML读取列表列表中的复杂对象其他注意事项总