【数据结构】二叉树全攻略,从实现到应用详解

 💎所属专栏:数据结构与算法学习 

💎 欢迎大家互三: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;}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3245474.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java18的主要新特性总结

目录 概述 变动说明 重要变更和信息 下载地址 Java18新特性总结 1、JEP 420: Switch 的模式匹配&#xff08;第二次预览&#xff09; 功能进化 Switch 模式匹配 类型标签 null标签 守卫标签 2、JEP 400&#xff1a;默认UTF-8编码 3、JEP 408&#xff1a;简易Web服务…

Java 虚拟线程:案例研究

一. 关键要点 虚拟线程是 Java 并发编程的一个重要进步&#xff0c;但在运行典型的云原生 Java 工作负载方面&#xff0c;它们并不比 Open Liberty 现有的自主线程池具有明显的优势。对于 CPU 密集型工作负载&#xff0c;由于目前尚不清楚的原因&#xff0c;虚拟线程的吞吐量低…

Idea如何快速高效的修改项目的包名

文章目录 前言一、全局替换的快捷键二、弹出如下的界面 前言 当我们有时候在做项目迁移的时候&#xff0c;需要快速的修改项目的包名&#xff01;那么如何快速高效的修改项目的报名呢&#xff1f; 经过尝试了很多方法&#xff01;最简单的方法就是利用全局替换来直接替换报名&…

QT实现带动态弹出动画的自定义通知提示框

Qt中经常会用到提示框&#xff0c;用于交互操作&#xff01;QMessageBox是被大多数人用到的&#xff0c;用起来是很方便&#xff0c;但是控件类型、大小、布局、样式、往往不是开发者想要的。本实例实现的Notification控件&#xff0c;是一种悬浮在角落的通知提醒框。 一、简述…

Day07-ES集群加密,kibana的RBAC实战,zookeeper集群搭建,zookeeper基本管理及kafka单点部署实战

Day07-ES集群加密&#xff0c;kibana的RBAC实战&#xff0c;zookeeper集群搭建&#xff0c;zookeeper基本管理及kafka单点部署实战 0、昨日内容回顾:1、基于nginx的反向代理控制访问kibana2、配置ES集群TSL认证:3、配置kibana连接ES集群4、配置filebeat连接ES集群5、配置logsta…

Mysql-错误处理: Found option without preceding group in config file

1、问题描述 安装MYSQL时&#xff0c;在cmd中“初始化”数据库时&#xff0c;输入命令&#xff1a; mysqld --initialize --consolecmd报错&#xff1a; D:\mysql-5.7.36-winx64\bin>mysql --initialize --console mysql: [ERROR] Found option without preceding group …

打印室预约小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;附近打印店管理&#xff0c;文件打印管理&#xff0c;当前预约管理&#xff0c;预约历史管理&#xff0c;打印记录管理 开发系统&#xff1a;Windows 架构模式&#xff1a;SSM JD…

linux服务器如何创建Raid10阵列,删除raid10

文章目录 1&#xff0c;首先查看一下机器上有几块盘2&#xff0c;构建raid10阵列3&#xff0c;把制作好的 RAID 磁盘阵列格式化为 ext4 格式4&#xff0c;创建挂载点然后把硬盘设备进行挂载操作5&#xff0c;查看/dev/md0 磁盘阵列的详细信息6&#xff0c;删除raid10 1&#xf…

理解深度学习中的过拟合和Dropout

新书速览|PyTorch深度学习与企业级项目实战-CSDN博客 随着迭代次数的增加&#xff0c;我们可以发现测试数据的loss值和训练数据的loss值存在着巨大的差距&#xff0c; 如图4-8所示&#xff0c;随着迭代次数的增加&#xff0c;training loss越来越好&#xff0c;但test loss却越…

分布式缓存-Redis持久化

使用缓存的时候&#xff0c;我们经常需要对内存中的数据进行持久化&#xff08;将内存中的数据写入到硬盘中&#xff09;。 原因&#xff1a;重用数据&#xff08;比如重启机器、机器故障之后恢复数据&#xff09;&#xff0c;做数据同步&#xff08;比如 Redis 集群的主从节点…

广告投放的智能优化:Kompas.ai如何提高广告效果

在数字广告领域&#xff0c;智能优化已成为提升广告投放效果和投资回报率(ROI)的关键。Kompas.ai&#xff0c;一款先进的广告智能优化工具&#xff0c;利用数据分析和机器学习技术&#xff0c;帮助广告主实现更精准、高效的广告投放。 智能优化在提升广告效果中的作用 智能优化…

微调 Florence-2 - 微软的尖端视觉语言模型

Florence-2 是微软于 2024 年 6 月发布的一个基础视觉语言模型。该模型极具吸引力&#xff0c;因为它尺寸很小 (0.2B 及 0.7B) 且在各种计算机视觉和视觉语言任务上表现出色。 Florence 开箱即用支持多种类型的任务&#xff0c;包括: 看图说话、目标检测、OCR 等等。虽然覆盖面…

MySQL字符串魔法:拼接、截取、替换与定位的艺术

在数据的世界里&#xff0c;MySQL作为一把强大的数据处理利剑&#xff0c;其字符串处理功能犹如魔术师手中的魔法棒&#xff0c;让数据变换自如。今天&#xff0c;我们就来一场关于MySQL字符串拼接、截取、替换以及查找位置的奇幻之旅&#xff0c;揭开这些操作的神秘面纱。 介绍…

谷歌浏览器114之前、126、127、128版本驱动下载,实时更新

114之前版本下载链接在这里 126以后版本下载链接在此&#xff0c;只有后面status是绿色对勾的才可以下载&#xff0c;**驱动大版本一致就可以使用&#xff0c;不需版本号一模一样&#xff1b;**下载所需版本只需点击对应的版本名称即可跳转到对应版本的下载位置。 以正式版为例…

FullCalendar日历组件集成实战(20)

背景 有一些应用系统或应用功能&#xff0c;如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件&#xff0c;但功能比较简单&#xff0c;用来做数据展现勉强可用。但如果需要进行复杂的数据展示&#xff0c;以及互动操作如通过点击添加事件&#xff0…

C# modbus 图表

控件&#xff1a;chart1(图表)&#xff0c;cartesianChart1(第三方添加图表)&#xff0c;timer(时间) 添加第三方&#xff1a; 效果&#xff1a;图标会根据连接的温度&#xff0c;湿度用timer时间进行改变 Chart1控件样式&#xff1a;Series添加线条&#xff0c;颜色&#xf…

编程从零基础到进阶(更新中)

题目描述 依旧是输入三个整数&#xff0c;要求按照占8个字符的宽度&#xff0c;并且靠左对齐输出 输入格式 一行三个整数&#xff0c;空格分开 输出格式 输出它们按格式输出的效果&#xff0c;占一行 样例输入 123456789 -1 10 样例输出 123456789-1 10 #include "stdio.…

which 命令在Linux中是一个快速查找可执行文件位置的工具

文章目录 0、概念1、which --help2、which命令解释 0、概念 which命令用于查找命令的可执行文件的路径which 命令在 Linux 中用于查找可执行命令的完整路径。当你在 shell 中输入一个命令时&#xff0c;shell 会在环境变量 $PATH 定义的目录列表中查找这个命令。which 命令可以…

基于Python+Flask+SQLite的豆瓣电影可视化系统

FlaskMySQLEcharts 基于PythonFlaskSQLite的豆瓣电影可视化系统 Echarts 不支持登录注册&#xff0c;并且信息存储在数据库中 不含爬虫代码&#xff0c;或爬虫代码已失效 简介 基于PythonFlaskMySQL的豆瓣电影可视化系统&#xff0c;采用Echart构建图表&#xff0c;支持自定…

ARM架构与FreeRTOS中的内存管理(flash与SRAM,堆栈)

在ARM架构中&#xff0c;内存的地址空间是如何划分的&#xff0c;内存映射表是怎样的 在Cortex-M7中&#xff0c;存储器一共有4GB的地址空间&#xff0c;4GB的地址空间又被划分为8个区域块&#xff0c;每个块有512M的内存。 Note&#xff1a;4GB的地址空间为 0x0000 0000 - 0…