【数据结构】二叉树全攻略,从实现到应用详解
💎所属专栏:数据结构与算法学习
💎 欢迎大家互三:2的n次方_
🍁1. 树形结构的介绍
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
以下是树的一些基本术语
节点的度:一个节点含有子树的个数
树的度:一棵树中所有节点度的最大值
叶子节点(终端节点):度为0的节点
双亲节点(父节点):一个节点的直接前驱节点
孩子节点(子节点):一个节点(除了根节点)的直接后继节点
根节点:没有双亲节点的节点
🍁2. 二叉树的介绍
二叉树是每个节点最多有两个子树的树结构,通常称为左子树和右子树,正如名字一样,每一个节点最多有两个子树。
🍁2.1 二叉树的类别
二叉树是树形结构中最重要的一种类型,它有多种特殊形态,如:
- 完全二叉树:除了最后一层外,每一层都被完全填满,并且所有节点都尽可能地向左对齐。
- 满二叉树:除了叶子节点外,每个节点都有两个子节点。
- 平衡二叉树(如AVL树、红黑树):任何节点的两个子树的高度最大差别为一。
- 搜索二叉树(BST):左子树上所有节点的值均小于它的根节点的值,右子树上所有节点的值均大于它的根节点的值。
🍁2.2 二叉树的基本性质
对于任意一棵二叉树,深度为 k 的二叉树,最多有 2的k次方 - 1 个节点。
在任何一棵二叉树中,如果度为2的节点数为 n₂,叶节点数为 n₀,则有关系式 n₀=n₂+1。
任意一棵包含 n 个节点的二叉树的高度至少为 log₂(n+1)(即完全二叉树的高度),最多为 n(即所有节点构成一个链表)。
在具有2 n 个节点的完全二叉树中,叶子节点的个数为 n,2n - 1个节点的完全二叉树中,叶子节点的个数为 n
🍁 2.3 二叉树的存储
二叉树可以通过链式存储和顺序存储的方式存储,这一节主要介绍链式存储
链式存储方式使用节点(Node)对象来表示二叉树的结构。每个节点包含数据部分和两个指针,分别指向其左子节点和右子节点。
例如使用孩子兄弟表示法存储树的效果如下图所示:
🍁3. 二叉树的实现
class TreeNode {int val;TreeNode left;//左孩子TreeNode right;//右孩子TreeNode(int x) {val = x;}
}
🍁3.1 二叉树的遍历
树的遍历是树的基本操作之一,常见的遍历方式有:
- 前序遍历:先访问根节点,然后遍历左子树,最后遍历右子树。
- 中序遍历:在二叉搜索树中,先遍历左子树,然后访问根节点,最后遍历右子树。
- 后序遍历:先遍历左子树,然后遍历右子树,最后访问根节点。
- 层序遍历:按从上到下、从左到右的顺序访问树中的每个节点
🍁3.1.1 先序,中序,后序遍历
//先序遍历,根左右public void preOrder(TreeNode root){if(root == null) return;System.out.print(root.val + " ");preOrder(root.left);preOrder(root.right);}//中序遍历,左根右public void inOrder(TreeNode root){if(root == null) return;inOrder(root.left);System.out.print(root.val + " ");inOrder(root.right);}//后序遍历,左右根public void postOrder(TreeNode root){if(root == null) return;postOrder(root.left);postOrder(root.right);System.out.print(root.val + " ");}
🍁3.1.2 层序遍历
层序遍历的实现需要借助队列来实现,由于队列先进先出的特性,可以依次把头结点,左孩子和右孩子依次入队,接着出队打印,就可以实现层序遍历的效果
public void levelOrder(TreeNode root) {if (root == null) return;Queue<TreeNode> q = new LinkedList<>();TreeNode cur = root;q.offer(root);while (!q.isEmpty()) {cur = q.poll();System.out.print(cur.val + " ");if (cur.left != null) q.offer(cur.left);if (cur.right != null) q.offer(cur.right);}}
102. 二叉树的层序遍历
可以试一下这道力扣上的题
这道题对返回值有了要求,其它的还是正常的层序遍历,答案的形式就是每一层作为一个数组,最终的答案以一个二维顺序表的形式返回
只需要每次入队时计算一下当前队列的元素,把当前层的元素都出队,每次入队的元素也都是下一层的元素
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();if (root == null) return res;Queue<TreeNode> q = new LinkedList<>();TreeNode cur = root;q.offer(root);while (!q.isEmpty()) {List<Integer> list = new ArrayList<>();int size = q.size();//当这一层的元素都出队后,下一层的元素也都能入队while (size!=0) {cur = q.poll();list.add(cur.val);if (cur.left != null) q.offer(cur.left);if (cur.right != null) q.offer(cur.right);size--;}//添加每层的答案res.add(list);}return res;}
}
🍁3.2 size()
求节点数
这里给出遍历和子问题两种思想进行实现
通过前序遍历的方法,通过计数的方式得到二叉树的节点数,分解子问题就是一棵二叉树的每个分支又可以看作一棵二叉树,整个二叉树的节点数就是左子树加上右子树再加上根节点数,根结点数就是1
public static int sizeNode = 0;//遍历思想public int size(TreeNode root) {if (root == null) return 0;sizeNode++;size(root.left);size(root.right);return sizeNode;}//子问题思想public int size2(TreeNode root) {if (root == null) return 0;return size2(root.left) + size2(root.right) + 1;}
🍁3.3 getLeafNodeCount(TreeNode root)
求叶子节点数
依然可以使用两种方法,通过遍历找出叶子节点,分解子问题就是左子树的叶子节点加上右子树的叶子节点等于二叉树的叶子节点,因为根节点肯定不是叶子节点
public static int leafSize = 0;public int getLeafNodeCount(TreeNode root) {if (root == null) return 0;//判断叶子节点if (root.left == null && root.right == null) {leafSize++;}getLeafNodeCount(root.left);getLeafNodeCount(root.right);return leafSize;}public int getLeafNodeCount2(TreeNode root) {if (root == null) return 0;if (root.left == null && root.right == null) return 1;return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);}
🍁3.4 getKLeveLNodeCount(TreeNode root, int k)
获取第 k 层的节点数
public int getKLeveLNodeCount(TreeNode root, int k) {if (root == null) {return 0;}if (k == 1) return 1;return getKLeveLNodeCount(root.left, k - 1) + getKLeveLNodeCount(root.right, k - 1);}
🍁3.5 getHeight(TreeNode root)
获取二叉树的高度
还是通过递归来实现,二叉树的高度其实也就是左子树和右子树的最大值,再加上根节点的一层,就是整棵树的高度
public int getHeight(TreeNode root) {if (root == null) return 0;return Math.max(getHeight(root.left),getHeight(root.right)) + 1;}
🍁3.6 findVal(TreeNode root,char val)
检测val是否存在二叉树中
只需要依次判断根节点,左子树,右子树,通过分解子问题,左子树又可以分为根节点,左子树右子树,依次达到遍历整棵树的效果,判断val是否存在
public TreeNode findVal(TreeNode root,char val){if(root == null) return null;if(root.val == val) return root;TreeNode t1 = findVal(root.left,val);if(t1 != null) return t1;TreeNode t2 = findVal(root.right,val);if(t2!= null) return t2;return null;}
🍁3.7 isCompleteTree(TreeNode root)
判断是否为完全二叉树
当遍历二叉树时,如果遍历到的cur节点此时为null,并且此时队列中剩余元素也都是null,那么就是完全二叉树
反之,如果剩余元素有不为null的,那么就不是完全二叉树,例如下面的图中,当遍历到B的左孩子为null时,此时队列中还有E,G等不为null的元素
public boolean isCompleteTree(TreeNode root) {if (root == null) return false;Queue<TreeNode> q = new LinkedList<>();q.offer(root);//找到cur为空时的位置while (!q.isEmpty()) {TreeNode cur = q.poll();if (cur != null) {q.offer(cur.left);q.offer(cur.right);}else {break;}}//继续判断剩余队列是否有不为null的元素while(!q.isEmpty()){if(q.peek()!=null) return false;q.poll();}return true;}
相关文章:
【数据结构】二叉树全攻略,从实现到应用详解
💎所属专栏:数据结构与算法学习 💎 欢迎大家互三:2的n次方_ 🍁1. 树形结构的介绍 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做…...
微信小程序加载动画文件
最近在做微信小程序的动画,调研了几种方案 PAG 腾讯自家的,分为完整版和lite版,对于矢量动画挺好的,但是位图会有问题 完整版会逐渐卡死,lite虽然不会卡死,但是很模糊,优点是动画文件很的很小。…...
[计算机网络] VPN技术
VPN技术 1. 概述 虚拟专用网络(VPN)技术利用互联网服务提供商(ISP)和网络服务提供商(NSP)的网络基础设备,在公用网络中建立专用的数据通信通道。VPN的主要优点包括节约成本和提供安全保障。 优…...
SQL 中的 EXISTS 子句:探究其用途与应用
目录 EXISTS 子句简介语法 EXISTS 与 NOT EXISTSEXISTS 子句的工作原理实际应用场景场景一:筛选存在关联数据的记录场景二:优化查询性能 EXISTS 与其他 SQL 结构的比较EXISTS vs. JOINEXISTS vs. IN 多重 EXISTS 条件在 UPDATE 语句中使用 EXISTS常见问题…...
OpenSearch分析WAF日志
Web应用防火墙(WAF)是保护web应用程序的重要工具,而分析WAF日志可以帮助我们更好地了解安全威胁并优化防护策略。本文将介绍15个使用OpenSearch分析WAF日志的实用例子,涵盖基础统计、安全分析、性能监控等多个方面。 准备工作 在开始之前,请确保: WAF日志已经被发送到OpenSea…...
【前端】零基础学会编写CSS
一、什么是CSS CSS (Cascading Style Sheets,层叠样式表)是一种是一种用来为结构化文档(如 HTML 文档)添加样式(字体、间距和颜色等)的计算机语言,能够对网页中元素位置的排版进行像素级别的精…...
Day07-ES集群加密,kibana的RBAC实战,zookeeper集群搭建,zookeeper基本管理及kafka单点部署实战
Day07-ES集群加密,kibana的RBAC实战,zookeeper集群搭建,zookeeper基本管理及kafka单点部署实战 0、昨日内容回顾:1、基于nginx的反向代理控制访问kibana2、配置ES集群TSL认证:3、配置kibana连接ES集群4、配置filebeat连接ES集群5、配置logsta…...
RK3568 V1.4.0 SDK,USB OTG端子不能被电脑识别出adb设备,解决
修改后的/usr/bin/usbdevice: #!/bin/sh # # Usage: # usbdevice [start|update|stop] # # Hookable stages: # usb_<pre|post>_<init|prepare|start|stop|restart>_hook # <usb function>_<pre|post>_<prepare|start|stop>_hook # # Example …...
如何在 Ubuntu 14.04 服务器上使用 Nginx 安装和保护 phpMyAdmin
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 介绍 像 MySQL 这样的关系型数据库管理系统在许多网站和应用程序中都是必不可少的。然而,并非所有用户都习惯通过命令行来管…...
redis存入hash,key=>value和key=>(key=>value)使用Python举例
在 Redis 中,HASH 数据结构(也称为 HMAP 或 Hash Map)允许你存储键值对集合,其中每个键值对都是字段(field)和值(value)的映射。在 Python 中,你可以使用 redis-py 库来与…...
Guava LocalCache源码分析:LocalCache的get、put、expand、refresh、remove、clear、cleanUp
Guava LocalCache源码分析:LocalCache的get、put、expand 前言一、get二、put三、expand 前言 上篇文章,详细描写了Guava LocalCache怎样如ConcurrentHashMap对缓存数据进行了分段存储。本章主要针对LocalCache重要的几个接口进行说明。 一、get CanIg…...
linux-arm ubuntu18.04 qmqtt5.12.6 编译部署
安装 qt 查看qt 版本 : qmake -v 下载对应版本 qmqtt 解压下载的mqtt文件 进入qmqtt xxx/src 目录 在qt 安装目录中创建QtMqtt文件夹, - x86平台qt 默认目录为 /usr/include/x86_64-linux-gnu/qt5 - arm平台qt 默认目录为/us…...
阿里ChatSDK使用,开箱即用聊天框
介绍: 效果:智能助理 ChatSDK,是在ChatUI的基础上,结合阿里云智能客服的最佳实践,沉淀和总结出来的一个开箱即用的,可快速搭建智能对话机器人的框架。它简单易上手,通过简单的配置就能搭建出对…...
LangChain —— Message —— How to trim messages
文章目录 一、概述二、获取最后的 max_tokens 令牌三、获取第一个 max_tokens 令牌四、编写自定义令牌计数器五、连成链六、使用 ChatMessageHistory 一、概述 所有模型都有 有限的 上下文窗口,这意味着它们可以作为输入的 token 数量是有限的。如果你有很长的消息&…...
专升本-1.0.3(英语)-升本209天-星期二
自己要耐得住寂寞,守得住自己的初心,守得住自己的未来,然后不断地真实地面对自己,使自己不断地获得一个真实地成长,说真话办真事,自己总会有一条路了,说真话,办真事的那条路才是最为…...
集合媒体管理、分类、搜索于一体的开源利器:Stash
Stash:强大的媒体管理工具,让您的影音生活井井有条- 精选真开源,释放新价值。 概览 Stash是一个专为个人媒体管理而设计的开源工具,基于 Go 编写,支持自部署。它以用户友好的界面和强大的功能,满足了现代用…...
数仓工具—Hive语法之事务表更新Transactional Table Update
Hive事务表更新 众所周知,Apache Hive 是建立在 Hadoop HDFS 之上的数据仓库框架。由于它包含表,您可能希望根据数据的变化更新表记录。直到最近,Apache Hive 还不支持事务。从 Hive 0.14 及以上版本开始支持事务性表。您需要启用 ACID 属性才能在 Hive 查询中使用更新、删…...
系统架构师(每日一练2)
每日一练 1.为实现对象重用,COM支持两种形式的对象组装,在()重用形式下,一个外部对象拥有指向一个内部对象的唯一引用,外部对象只是把请求转发给内部对象;在()重用形式下,直接把内部对象的接口引用传给外部对象的客户…...
Django REST Framework(十)视图集-ViewSet
视图集(ViewSet)是 Django REST framework 中的一个高级特性,它允许你使用更少的代码来实现标准的 CRUD(创建、读取、更新、删除)操作。ViewSet 类本质上是基于 GenericAPIView 的,但它们提供了更多的默认行…...
sping总览
一、spring体系 1. spring是什么? 轻量级的开源的J2EE框架。它是一个容器框架,主要实现了ioc,同时又通过aop实现了面向切面编程,它又是一个中间层框架(万能胶)可以起一个连接作用,比如说把myba…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

