赫夫曼树(java)

2024-01-28 18:48
文章标签 java 夫曼

本文主要是介绍赫夫曼树(java),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、基本概念

1.1  什么是赫夫曼树

1.2  什么是权值 

1.3  什么是路径 

1.4  什么是带权路径长度(WPL) 

1.5  举例说明

二、如何构建赫夫曼树

2.1  明确给定值

2.2  明确赫夫曼树的特点

2.3  实现赫夫曼树

2.4  关于实现赫夫曼树过程中的一点理解

三、赫夫曼树的代码实现

3.1  定义具有权值属性的结点类

3.2  构建赫夫曼树

3.3  完整代码实现

四、小结


一、基本概念

1.1  什么是赫夫曼树

  • 给定N个权值作为N个叶子结点,构造一颗二叉树;
  • 该树的带权路径长度(WPL)最小;
  • 权值越大的结点离根节点越近; 

1.2  什么是权值 

  • 百科:将树中结点赋给一个有着某种含义的数值。什么意思???我的理解是将数值赋给结点类中的一个变量,那么结点本身就有了权值这个属性,但是我没看懂这个定义。

1.3  什么是路径 

  • 从父结点到达其孩子结点或者孙子结点之间的通路;
  • 若根结点的层数规定为1,那么从根结点到L层结点的路径长度为L-1; 

1.4  什么是带权路径长度(WPL) 

  • 规定WPL为所有叶子结点的带权路径之和;
  • 叶子结点的WPL = 该叶子结点的权值 * 从根结点到该叶子结点的路径长度;

1.5  举例说明

  • 叶子结点上标注的值就是权值;
  • 对于A,根结点为第1层,值为13的叶子结点在第3层,那么从根结点到该结点的路径长度为3 - 1 = 2;
  • 对于A,值为13的叶子结点的WPL = 13 * 2 = 26;
  • 那么A的WPL = WPL1 + WPL2 + WPL3 + WPL4  = 62;
  • 上面三棵树中,根据赫夫曼树的定义,只有B是赫夫曼树;

二、如何构建赫夫曼树

2.1  明确给定值

  • 给定的是N个带有权值的叶子结点;                       

2.2  明确赫夫曼树的特点

  • 权值越小的结点离根结点越远,这点很关键;

2.3  实现赫夫曼树

  • 定义结点类并加入权值属性,将数组中的值赋给结点;
  • 将带有权值的结点加入到集合中,并从小到大排序;
  • 找到权值最小的两个叶子结点,创建新的结点,其左右孩子指向这两个结点;
  • 从集合中移除上述两个叶子结点,并加入新创建的结点;
  • 重复上述2-4步,直到集合中只有一个元素,直接返回;

2.4  关于实现赫夫曼树过程中的一点理解

  • 当叶子结点从集合中移除后,其仍在内存中,这样我们创建的这棵小树的逻辑结构还在,这就是最底下的二叉树;

 

  • 重新对集合中的元素排序后,按照同样的方式,能得到上一层的树结构;

 

  • 最后得到最优二叉树,也就时赫夫曼树;

 

三、赫夫曼树的代码实现

3.1  定义具有权值属性的结点类

/*** 这是结点类,实现Comparable接口是为了能够排序* @author Administrator**/
class Node implements Comparable<Node> {int value;Node left;Node right;// 构造方法public Node(int value) {this.value = value;}@Overridepublic String toString() {return "" + value;}// 前序遍历public void preOrder() {System.out.print(this + " ");if (this.left != null) {this.left.preOrder();}if (this.right != null) {this.right.preOrder();}}// 这个表示从小到大@Overridepublic int compareTo(Node o) {return this.value - o.value;}
}

3.2  构建赫夫曼树

// 这个方法用来构建赫夫曼树public static Node createHuffmanTree(int[] arr) {// 创建存放结点的集合List<Node> nodes = new ArrayList<Node>();// 将带有权值的结点加入集合for (int value : arr) {nodes.add(new Node(value));}// 开始构建赫夫曼树while (nodes.size() > 1) {// 对集合排序Collections.sort(nodes);// 取出权值最小的两个结点Node leftnode = nodes.get(0);Node rightnode = nodes.get(1);// 创建新的结点,构建小树Node parent = new Node(leftnode.value + rightnode.value);parent.left = leftnode;parent.right = rightnode;// 从集合中移除权值最小的两个结点,并将新结点加入nodes.remove(leftnode);nodes.remove(rightnode);nodes.add(parent);}return nodes.get(0);}

3.3  完整代码实现

package practice;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** 这关于是赫夫曼树的练习* @author Administrator**/
public class HuffmanTree {public static void main(String[] args) {int[] arr = { 8, 3, 7, 13 };Node root = createHuffmanTree(arr);preOrder(root);}// 这个方法用于前序遍历public static void preOrder(Node root) {if (root != null) {root.preOrder();} else {System.out.println("空树,无法遍历");}}// 这个方法用来构建赫夫曼树public static Node createHuffmanTree(int[] arr) {// 创建存放结点的集合List<Node> nodes = new ArrayList<Node>();// 将带有权值的结点加入集合for (int value : arr) {nodes.add(new Node(value));}// 开始构建赫夫曼树while (nodes.size() > 1) {// 对集合排序Collections.sort(nodes);// 取出权值最小的两个结点Node leftnode = nodes.get(0);Node rightnode = nodes.get(1);// 创建新的结点,构建小树Node parent = new Node(leftnode.value + rightnode.value);parent.left = leftnode;parent.right = rightnode;// 从集合中移除权值最小的两个结点,并将新结点加入nodes.remove(leftnode);nodes.remove(rightnode);nodes.add(parent);}return nodes.get(0);}
}
/*** 这是结点类,实现Comparable接口是为了能够排序* @author Administrator**/
class Node implements Comparable<Node> {int value;Node left;Node right;// 构造方法public Node(int value) {this.value = value;}@Overridepublic String toString() {return "" + value;}// 前序遍历public void preOrder() {System.out.print(this + " ");if (this.left != null) {this.left.preOrder();}if (this.right != null) {this.right.preOrder();}}// 这个表示从小到大@Overridepublic int compareTo(Node o) {return this.value - o.value;}
}

四、小结

  • 代码并不难理解,但是关于赫夫曼树的了解还太少,坚持学习,应该会有更深入的理解。

这篇关于赫夫曼树(java)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

springboot健康检查监控全过程

《springboot健康检查监控全过程》文章介绍了SpringBoot如何使用Actuator和Micrometer进行健康检查和监控,通过配置和自定义健康指示器,开发者可以实时监控应用组件的状态,... 目录1. 引言重要性2. 配置Spring Boot ActuatorSpring Boot Act

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python