华为OD机试真题---生成哈夫曼树
华为OD机试中关于生成哈夫曼树的题目通常要求根据给定的叶子节点权值数组,构建一棵哈夫曼树,并按照某种遍历方式(如中序遍历)输出树中节点的权值序列。以下是对这道题目的详细解析和解答思路:
一、题目要求
给定一个长度为n的正整数数组,每个数字代表二叉树叶子节点的权值。要求生成一棵哈夫曼树,并将其按中序遍历的顺序输出。树中每个非叶子节点的权值等于其左右子节点权值之和。对于权值相同的两个节点,左子树的高度应小于等于右子树的高度。在满足上述条件的前提下,左子节点的权值应小于等于右子节点的权值。
二、哈夫曼树简介
哈夫曼树是一种带权最优二叉树,其特点是带权路径长度最短。所谓带权路径长度,是指树中所有叶子节点的权值乘上其到根节点的路径长度(若根节点为0层,则叶子节点到根节点的路径长度为叶子节点的层数)之和。
三、解题思路
- 构建森林:将每个叶子节点看作一棵独立的树,并将这些树放入一个优先队列(最小堆)中。优先队列用于每次选择权值最小的两个节点进行合并。
- 合并节点:从优先队列中取出权值最小的两个节点,将它们作为新树的左右子树,并计算新树的权值为两棵子树权值之和。然后,将新树加入优先队列中。
- 重复合并:重复上述步骤,直到优先队列中只剩下一棵树,这棵树即为所求的哈夫曼树。
- 中序遍历:对构建好的哈夫曼树进行中序遍历,得到节点权值序列,并按要求输出。
四、代码实现
import java.util.*;class HuffmanNode implements Comparable<HuffmanNode> {int weight;HuffmanNode left, right;HuffmanNode(int weight) {this.weight = weight;this.left = this.right = null;}@Overridepublic int compareTo(HuffmanNode other) {return this.weight - other.weight;}
}public class HuffmanTree {/*** 构建哈夫曼树* 哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树* 在数据压缩、编码等领域有广泛的应用** @param weights 每个节点的权重,权重越小的节点,在构建哈夫曼树时,越靠近根节点* @return 返回哈夫曼树的根节点*/public static HuffmanNode buildHuffmanTree(int[] weights) {// 优先队列,用于存储哈夫曼树的节点,队列头部元素权值最小PriorityQueue<HuffmanNode> pq = new PriorityQueue<>();// 遍历所有节点权重,初始化哈夫曼树节点并加入优先队列for (int weight : weights) {pq.add(new HuffmanNode(weight));}// 当优先队列中节点数量大于1时,循环构建哈夫曼树while (pq.size() > 1) {// 从优先队列中取出权值最小的两个节点HuffmanNode left = pq.poll();HuffmanNode right = pq.poll();// 断言right节点非空,确保树能正常构建assert right != null;// 创建新的哈夫曼节点,作为left和right节点的父节点,其权重为两个子节点权重之和HuffmanNode parent = new HuffmanNode(left.weight + right.weight);// 设置父节点的左右子节点parent.left = left;parent.right = right;// 将新的父节点加入优先队列pq.add(parent);}// 返回优先队列中剩余的唯一节点,即哈夫曼树的根节点return pq.poll();}/*** 中序遍历哈夫曼树* 中序遍历的特点是左子树-根节点-右子树的顺序访问树中的节点* 这种遍历顺序在哈夫曼树中主要用于验证树的结构,而不用于构建最短编码** @param root 哈夫曼树的根节点* @param result 用于存储遍历结果的列表,通常是节点的权重*/public static void inorderTraversal(HuffmanNode root, List<Integer> result) {// 判断当前节点是否为空,为空则直接返回if (root == null) {return;}// 递归中序遍历左子树inorderTraversal(root.left, result);// 将当前节点的权重添加到结果列表中result.add(root.weight);// 递归中序遍历右子树inorderTraversal(root.right, result);}/*** 主函数入口* 本程序用于演示霍夫曼树的构建及其遍历过程* 霍夫曼树是一种带权路径长度最短的二叉树,具有重要应用价值** @param args 命令行参数*/public static void main(String[] args) {// 创建Scanner对象,用于读取命令行输入Scanner scanner = new Scanner(System.in);// 读取霍夫曼树节点数量int n = scanner.nextInt();// 初始化霍夫曼树节点权重数组int[] weights = new int[n];// 读取每个节点的权重for (int i = 0; i < n; i++) {weights[i] = scanner.nextInt();}// 构建霍夫曼树并返回根节点HuffmanNode root = buildHuffmanTree(weights);// 初始化用于存储中序遍历结果的列表List<Integer> result = new ArrayList<>();// 中序遍历霍夫曼树,并将结果存储到列表中inorderTraversal(root, result);// 输出中序遍历结果for (int weight : result) {System.out.print(weight + " ");}}
}
五、代码解析
-
HuffmanNode 类:
HuffmanNode
是一个表示哈夫曼树节点的类。- 它包含三个属性:
weight
(节点权重),left
(左子节点),right
(右子节点)。 - 实现了
Comparable<HuffmanNode>
接口,以便节点可以根据权重进行排序。
-
HuffmanTree 类:
- 包含构建哈夫曼树的静态方法
buildHuffmanTree
。 - 包含进行中序遍历的静态方法
inorderTraversal
。 main
方法用于读取输入、构建哈夫曼树、进行中序遍历并输出结果。
- 包含构建哈夫曼树的静态方法
-
main 方法:
- 读取节点数量
n
和每个节点的权重。 - 调用
buildHuffmanTree
方法构建哈夫曼树。 - 初始化结果列表
result
并调用inorderTraversal
方法进行中序遍历。 - 输出遍历结果。
- 读取节点数量
运行实例解析
输入:
5
5 15 40 30 10
步骤:
-
读取输入:
- 节点数量
n = 5
。 - 节点权重数组
weights = [5, 15, 40, 30, 10]
。
- 节点数量
-
构建哈夫曼树:
- 初始化优先队列
pq
并添加所有节点。 - 不断从
pq
中取出两个最小权重的节点,合并成一个新节点,并将新节点添加回pq
。 - 最终,
pq
中剩下的唯一节点即为哈夫曼树的根节点。
构建过程(可能的一种情况,因为合并顺序可能不同):
- 初始:
pq = [5, 10, 15, 30, 40]
- 合并
5
和10
,得到新节点15
,加入pq
:pq = [15, 15, 30, 40]
- 合并两个
15
,得到新节点30
,加入pq
:pq = [30, 30, 40]
- 合并
30
和30
,得到新节点60
,加入pq
:pq = [60, 40]
- 合并
60
和40
,得到根节点100
。
- 初始化优先队列
-
中序遍历:
- 由于哈夫曼树不是二叉搜索树,中序遍历的结果取决于节点的合并顺序和树的结构。
- 假设按上述构建过程,中序遍历结果可能是一种特定的节点权重顺序(注意,这不是唯一的)。
-
输出结果:
- 输出中序遍历得到的节点权重列表。
注意:由于哈夫曼树的构建过程中节点合并顺序可能不同(当存在相同权重的节点时),因此中序遍历的结果也可能不同。上述构建过程和中序遍历结果是基于一种假设的合并顺序。
六、实际输出
由于代码中的中序遍历会按照左子树-根节点-右子树的顺序访问节点,并且哈夫曼树的构建依赖于节点的合并顺序,因此实际输出将取决于具体的合并过程。要获得确切的输出,需要运行代码并观察结果。
如果您想要验证哈夫曼树的正确性,通常不会使用中序遍历,而是会检查每个节点的权重和从根到该节点的路径长度(用于计算哈夫曼编码的长度等)。中序遍历在这里主要用于演示和验证树的结构。
相关文章:

华为OD机试真题---生成哈夫曼树
华为OD机试中关于生成哈夫曼树的题目通常要求根据给定的叶子节点权值数组,构建一棵哈夫曼树,并按照某种遍历方式(如中序遍历)输出树中节点的权值序列。以下是对这道题目的详细解析和解答思路: 一、题目要求 给定一个…...

小红书新ID保持项目StoryMaker,面部特征、服装、发型和身体特征都能保持一致!(已开源)
继之前和大家介绍的小红书在ID保持以及风格转换方面相关的优秀工作,感兴趣的小伙伴可以点击以下链接阅读~ 近期,小红书又新开源了一款文生图身份保持项目:StoryMaker,是一种个性化解决方案,它不仅保留了面部的一致性&…...

Docker 环境下 GPU 监控实战:使用 Prometheus 实现 DCGM Exporter 部署与 GPU 性能监控
Docker 环境下 GPU 监控实战:使用 Prometheus 实现 DCGM Exporter 部署与 GPU 性能监控 文章目录 Docker 环境下 GPU 监控实战:使用 Prometheus 实现 DCGM Exporter 部署与 GPU 性能监控一 查看当前 GPU 信息二 dcgm-exporter 部署1)Docker r…...

联想小新打印机M7328w如何解决卡纸,卡了一个小角在里面,然后再次打印的时候,直接卡住,不能动了。灯显示红色。
1、今天打印一张纸,应该是不小心放歪了,打出来的也是有些斜,然后打出来缺少了个角。 图中的小纸就是从打印机的左边的角,用镊子取出来的,手不太好拿,所以拿个工具比较合适。 2、那么碰到这种卡纸应该如何处…...

软件可靠性之MTTR、MTBF、MTTF、MTTD区别
一.概念解释 1.MTBF(Mean Time Between Failures):指两次故障之间的平均时间,通常用于衡量设备或系统的可靠性。 2.MTTF(Mean Time to Failure):指设备或系统的平均无故障运行时间。 3.MTTR&am…...

Qt-QDockWidget浮动窗口相关操作(49)
目录 描述 使用 描述 在 Qt 中,浮动窗⼝也称之为铆接部件。浮动窗⼝是通过 QDockWidget类 来实现浮动的功能。浮动窗口⼀般是位于核心部件的周围,可以有多个。 使用 创建我们可以参考下面的语法格式 使用起来也很简单,不过只能创建一个 Q…...

图形用户界面-GUI的基本概念和组件之一
前言 GUI(Graphical User Interface,图形用户界面,简称图形界面)编程实际是引用java.awt或javax.swing类包中的窗口类、控制组件类、布局类、事件类等,通过将控制组件类,如菜单、按钮、文本框等,…...

【MATLAB代码】基于RSSI原理的蓝牙定位程序(N个锚点、三维空间),源代码可直接复制
文章目录 介绍主要功能技术细节适用场景程序结构运行截图源代码详细教程:基于RSSI的蓝牙定位程序1. 准备工作2. 代码结构2.1 清理工作环境2.2 定义参数2.3 生成锚点坐标2.4 定义信号强度与距离的关系2.5 模拟未知点的位置2.6 定位函数2.7 绘图2.8 输出结果2.9 定义定位函数3. …...

Pyenv 介绍和安装指南 - Ubuntu 24
原文: https://www.qiulin-dev.top/articles/81aab753-0d0e-470c-b08f-2643c876841b 1. Pyenv 介绍 Pyenv 是一个非常流行的 Python 版本管理工具,它可以让你在同一台机器上安装并管理多个不同的 Python 版本,解决了不同项目需要不同 Python…...

zookeeper实现RMI服务,高可用,HA
这可不是目录 1.RMI原理与说明1.1含义1.2流程1.3rmi的简单实现1.4RMI的局限性 2.zookeeper实现RMI服务(高可用、HA)2.1实现原理2.2高可用分析2.3zookeeper实现2.3.1代码分析2.3.2公共部分2.3.3服务端2.3.4客户端2.3.5运行与部署2.3.6效果展示与说明 1.RM…...

通过Express + Vue3从零构建一个用户认证与授权系统(一)项目结构设计
项目背景 本文基于 TypeScript Express Vue3 ,从零构建一个用户认证与授权管理系统。这个系统的核心部分包括前端、后端和数据库。我们需要确保各部分合理分层、易于维护和扩展,让我们一步步去实现我们的系统。 一、项目结构设计 1. 前端 (Vue 3 E…...

JavaScript 第13章:Ajax 与异步请求
在Web开发中,异步请求是一种非常重要的技术,它可以让网页在不重新加载的情况下与服务器交互。本章将介绍两种常用的异步请求技术:XMLHttpRequest 和 Fetch API,以及它们如何用于处理JSON数据交换,并通过一个实战案例—…...

速卖通商品详情接口技术解析及Python代码示例
速卖通商品详情接口技术解析及Python代码示例 速卖通(AliExpress)作为全球知名的跨境电商平台,其开放平台提供了丰富的API接口,允许开发者集成速卖通的各项功能,实现商品搜索、详情查询、订单管理等一系列操作。本文将…...

邻接表的有向网(C语言代码)
#include <stdio.h> #include <stdlib.h> #define MVNum 100 //最大顶点数 //边表结构体 typedef struct ArcNode { //表结点 int adjvex; //邻接点的位置 struct ArcNode* nextarc; //指向下一个…...

大模型生成PPT大纲优化方案:基于 nVidia NIM 平台的递归结构化生成
大模型生成PPT大纲优化方案:基于 nVidia NIM 平台的递归结构化生成 待解决的问题 生成PPT大纲是一种大模型在办公场景下应用的常见需求。 然而: 目前直接让大模型生成大纲往往是非结构化的,输出格式多样,难以统一和规范&#…...

MRSO算法(JCR2区)
原论文摘要:智能技术的快速发展促使利用自然行为来解决复杂问题的优化算法得以发展。其中,鼠群优化算法(Rat Swarm Optimizer,RSO)受老鼠的社会和行为特征启发,在各个领域已展现出潜力,但其收敛…...

最新Spring Boot3框架入门教程,基础知识讲解(参考官方文档),同时基于MybatisPlus+MYSQL搭建后台管理系统基础流程(附源码)
本文所涉及的代码以及相关文件均上传至仓库:GitHub - yang66-hash/XDPropertyManagementSystemDemo: This is a demo template based on SpringBoot3 in the background of property management system. Spring Boot 是由 Pivotal 团队开发的一款开源框架,它可以帮助…...

导数的概念及在模型算法中的应用
一. 导数概念与计算 1. 导数的物理意义: 瞬时速率。一般的,函数yf(x)在x处的瞬时变化率是 2. 导数的几何意义: 曲线的切线,当点趋近于P时,直线 PT 与曲线相切。容易知道,割线的斜率是当点趋近于 P 时&…...

获取首日涨停封盘后第二次交易日上涨/下跌的概率
有许多投资者喜欢在股票涨停封盘后,跟进买入。普通股民会认为一个能在今日涨停封盘的股票,证明其上市公司正有十分重大的利好信息,只需要跟进购买便可以获取短期利益。 我们用数据来看一下在当日涨停封盘后,第二次交易日是上涨还…...

shell $ 用法
Shell脚本中$符号的几种用法小结_linux shell_脚本之家 Shell 传递参数 | 菜鸟教程 $ 符号说明$0Shell 的命令本身1到9表示 Shell 的第几个参数$?显示最后命令的执行情况$#传递到脚本的参数个数$$脚本运行的当前进程 ID 号$*以一个单字符串显示所有向脚本传递的参数$!后台运行…...

如何用支付宝实现靠脸吃饭
还记得上学时,每当下课铃声响起,我们就会像一群脱缰的野马一样,浩浩荡荡地冲向食堂。最令人崩溃的时刻莫过于终于到达打饭窗口前排时,却发现饭卡忘带了!但现在,这种情况将不再发生。许多学校食堂已经配备了…...

Visual Studio的实用调试技巧总结
对于很多学习编程的老铁们来说,是不是也像下面这张图一样写代码呢? 那当我们这样编写代码的时候遇到了问题?大家又是怎么排查问题的呢?是不是也像下面这张图一样,毫无目的的一遍遍尝试呢? 这篇文章我就以 V…...

graphrag学习总结
学习视频:b站链接 项目链接 GraphRAG 的基本概念 Document(文档):系统中的输入文档。这些文档要么代表CSV中的单独行,要么代表单独的txt文件。 TextUnit(文本块):要分析的文本块。…...

专题:贪心算法(已完结)
1.分发饼干 方法一:用最大的胃口 找到最大的饼干(先遍历胃口) class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 主要思路 用最大的饼干找最大的胃口sort(g.begin(),g.end());so…...

Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式
单机模式 单机模式是Hadoop最简单的运行模式。在单机模式下,所有Hadoop组件都运行在单个机器上,包括HDFS、MapReduce等。由于只有一个节点参与计算,单机模式适用于开发和测试阶段,不适合用于处理大规模数据。在单机模式下…...

JavaScript将array数据下载到Excel中
具体代码如下: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widt…...

【前端】Bootstrap:快速开始
Bootstrap 是一个功能强大且易于使用的前端框架,专门用于创建响应式和移动优先的网页。学习Bootstrap不仅可以帮助你快速构建现代网页,还可以提升你对前端开发流程的理解。本教程将从基础概念开始,逐步引导你掌握Bootstrap,并通过…...

文献阅读(222) VVQ协议死锁
题目:VVQ: Virtualizing Virtual Channel for Cost-Efficient Protocol Deadlock Avoidance时间:2023会议:HPCA研究机构:KAIST request-reply协议死锁如下图所示,每个node收到request之后发送reply,但是想…...

Node.js管理工具NVM
nvm(Node Version Manager)是一个用于管理多个 Node.js 版本的工具。以下是 nvm 的使用方法和一些常见命令: 一、安装 nvm 下载 nvm: 地址:https://github.com/coreybutler/nvm-windows/releases访问 nvm 的 GitHub 仓…...

云原生后端
云原生后端(Cloud-Native Backend)是指在云计算环境中,利用云原生技术(如容器、微服务、服务网格等)构建和部署后端应用程序的一种方法。以下是对云原生后端的详细讲解: 1. 定义 云原生是一种设计和构建应…...