当前位置: 首页 > news >正文

二叉树_详解

目录

1. 树型结构

1.1 概念

1.2 概念

1.3 树的表示形式

1.4 树的应用 

2. 二叉树 

2.1 概念

2.2 两种特殊的二叉树

2.3 二叉树的性质

2.4 二叉树的存储

2.5 二叉树的基本操作

2.5.1 前置说明

2.5.2 二叉树的遍历

2.5.3 二叉树的基本操作


1. 树型结构

1.1 概念

树是一种非线性的数据结构,它是由nn>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
  • 有一个特殊的结点,称为根结点,根结点没有前驱结点
  • 除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1T2......Tm,其中每一个集合Ti (1 <= i <=m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
  • 树是递归定义的。

 

 注意:树形结构中,子树之间不能有交集,否则就不是树形结构

1.2 概念

结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为6
树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6
叶子结点或终端结点:度为0的结点称为叶结点; 如上图:BCHI...等节点为叶结点
双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:AB的父结点
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:BA的孩子结点
根结点:一棵树中,没有双亲结点的结点;如上图:A
结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
树的高度或深度:树中结点的最大层次; 如上图:树的高度为4
树的以下概念只需了解,在看书时只要知道是什么意思即可:
非终端结点或分支结点:度不为0的结点; 如上图:DEFG...等节点为分支结点
兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:BC是兄弟结点
堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:HI互为兄弟结点
结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
森林:由mm>=0)棵互不相交的树组成的集合称为森林

1.3 树的表示形式

树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如:双亲表示法孩子表示法孩子双亲表示法孩子兄弟表示法等等。我们这里就简单的了解其中最常用的孩子兄弟表示法
class Node {int value; // 树中存储的数据Node firstChild; // 第一个孩子引用Node nextBrother; // 下一个兄弟引用
}

1.4 树的应用 

        文件系统管理(目录和文件)

2. 二叉树 

2.1 概念

一棵二叉树是结点的一个有限集合,该集合:
1. 或者为空
2. 或者是由一个根节点加上两棵别称为左子树右子树的二叉树组成。

从上图可以看出:
1. 二叉树不存在度大于2的结点
2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
注意:对于任意的二叉树都是由以下几种情况复合而成的:

 

2.2 两种特殊的二叉树

1. 满二叉树: 一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且结点总数是
,则它就是满二叉树
2. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0n-1的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

 

2.3 二叉树的性质

1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有(i>0)个结点
2. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是(k>=0)
3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0n21
4. 具有n个结点的完全二叉树的深度k上取整
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有
  • i>0双亲序号:(i-1)/2i=0i为根结点编号,无双亲结点
  • 2i+1<n,左孩子序号:2i+1,否则无左孩子
  • 2i+2<n,右孩子序号:2i+2,否则无右孩子

2.4 二叉树的存储

二叉树的存储结构分为:顺序存储类似于链表的链式存储
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,具体如下:
// 孩子表示法
class Node {int val; // 数据域Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {int val; // 数据域Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树Node parent; // 当前节点的根节点
}
孩子双亲表示法后序在平衡树位置介绍,本文采用孩子表示法来构建二叉树。

2.5 二叉树的基本操作

2.5.1 前置说明

public class BinaryTree{public static class BTNode{BTNode left;BTNode right;int value;BTNode(int value){this.value = value;}}    private BTNode root;public void createBinaryTree(){BTNode node1 = new BTNode(1);BTNode node1 = new BTNode(2);BTNode node1 = new BTNode(3);BTNode node1 = new BTNode(4);BTNode node1 = new BTNode(5);BTNode node1 = new BTNode(6);root = node1;node1.left = node2;node2.left = node3;node1.right = node4;node4.left = node5;node5.right = node6;}
}
注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

2.5.2 二叉树的遍历

1. 前中后序遍历
二叉树结构,最简单的方式就是遍历。所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问访问结点所做的操作依赖于具体的应用问题(比如:打印节点内容、节点内容加1)。 遍历是二叉树上最重要的操作之一,是二叉树上进行其它运算之基础。

在遍历二叉树时,如果没有进行某种约定,每个人都按照自己的方式遍历,得出的结果就比较混乱,如果按照某种规则进行约定,则每个人对于同一棵树的遍历结果肯定是相同的。如果N代表根节点,L代表根节点的左子树,R代表根节点的右子树,则根据遍历根节点的先后次序有以下遍历方式:
  • NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点--->根的左子树--->根的右子树。
  • LNR:中序遍历(Inorder Traversal)——根的左子树--->根节点--->根的右子树。
  • LRN:后序遍历(Postorder Traversal)——根的左子树--->根的右子树--->根节点。

 

在前几篇文章中我已经写了二叉树的前中后序遍历,这里我就不在写了。

二叉树的前序遍历 

二叉树的中序遍历

二叉树的后续遍历

2. 层序遍历
层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

2.5.3 二叉树的基本操作

    /*获取叶子节点的个数:遍历思路*/public static int leafSize = 0;int getLeafNodeCount1(TreeNode root) {if (root == null){return 0;}Deque<TreeNode> queue = new LinkedList<>();queue.offer(root);while(!queue.isEmpty()){TreeNode node = queue.poll();if (node.left != null){queue.offer(node.left);}if (node.right != null){queue.offer(node.right);}if (node.left==null && node.right==null){leafSize++;}}return leafSize;}/*获取叶子节点的个数:子问题*/int getLeafNodeCount2(TreeNode root) {if (root == null){return 0;}if (root.right==null && root.left==null){return 1;}return getLeafNodeCount2(root.left)+getLeafNodeCount2(root.right);}/*获取第K层节点的个数*/int getKLevelNodeCount(TreeNode root, int k) {if (root==null || k<=0){return 0;}if (k == 1){return 1;}return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);}/*获取二叉树的高度时间复杂度:O(N)*/int getHeight(TreeNode root) {if (root == null){return 0;}if (root.left==null && root.right==null){return 1;}return 1+Math.max(getHeight(root.left),getHeight(root.right));}// 检测值为value的元素是否存在Boolean find(TreeNode root, char val) {if (root == null){return false;}if (root.val == val){return true;}return find(root.left,val)||find(root.right,val);}//层序遍历void levelOrder(TreeNode root) {Deque<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){TreeNode node = queue.poll();System.out.print(node.val + " ");if (node.left != null){queue.offer(node.left);}if (node.right != null){queue.offer(node.right);}}System.out.println();}// 判断一棵树是不是完全二叉树boolean isCompleteTree(TreeNode root) {Deque<TreeNode> queue = new LinkedList<>();queue.offer(root);boolean isStep1 = true;while(!queue.isEmpty()){TreeNode node = queue.poll();if(isStep1){if(node.left!=null && node.right!=null){queue.offer(node.left);queue.offer(node.right);}else if(node.left != null){queue.offer(node.left);isStep1 = false;}else if(node.right != null){return false;}else{isStep1 = false;}}else{if(node.left!=null || node.right!=null){return false;}}}return true;}

相关文章:

二叉树_详解

目录 1. 树型结构 1.1 概念 1.2 概念 1.3 树的表示形式 1.4 树的应用 2. 二叉树 2.1 概念 2.2 两种特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的基本操作 2.5.1 前置说明 2.5.2 二叉树的遍历 2.5.3 二叉树的基本操作 1. 树型结构 1.1 概念 …...

LOTO示波器电源环路增益分析客户实测

我们在之前有文章介绍过LOTO示波器信号源扫频测电源环路增益稳定性的方法和过程&#xff0c;可以参考演示视频如下&#xff1a; https://www.ixigua.com/7135738415382790663?logTaga843d537a27090d5117b 或者阅读对应的文章&#xff1a;《LOTO示波器 实测 开环增益频响曲线/电…...

Netty主要组件

: 在Netty中有很多重要的组件, 每个组件职业不同, 担负不同的功能。 组件一 NioEventLoop 在它的底层封装了Selector, 实现多路复用, 由唯一绑定的一个线程去进行三大步骤循环操作: 监听事件,处理事件,执行任务。 组件二 NioServerSocketChannel NioSocketChannel 一个是服务…...

Linux系统【centos7】常用基础命令教程

今天我来介绍一下Linux系统的基础知识。 首先&#xff0c;我们需要了解Linux是什么。Linux是一种免费且开放源代码的操作系统&#xff0c;它被广泛用于服务器、移动设备和嵌入式系统。 接下来&#xff0c;我们需要了解基本的Linux命令。其中一些基本命令包括&#xff1a; 1.…...

【Redis学习】Redis入门概述

Redis是什么 Redis:REmote Dictionary Server(远程字典服务器) 官网介绍&#xff1a;The open source, in-memory data store used by millions of developers as a database, cache, streaming engine, and message broker.&#xff08;被数百万开发人员用作数据库、缓存、流…...

nodejs微服务:Consul集群

Consule集群 1 &#xff09;概述 Consul是HashiCorp 公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置Consul是分布式的、高可用的、可横向扩展的, 完成consul的安装后&#xff0c;必须运行agentagent可以运行为 server模式、client模式, 每个数据中心至少…...

spring事务处理

系列文章目录 Spring中事务的处理相关内容的学习 文章目录系列文章目录前言一、Spring事务简介二、案例&#xff1a;银行账户转账1.题目要求和思路分析2.实现步骤3.实现结构三、spring事务角色四、spring事务相关配置五、案例&#xff1a;转账业务追加日志1.题目要求和思路分析…...

2023 年博客之星的入围规则

目的 感谢各位博主和社区的大力支持&#xff0c;我们的博客之星活动成为了 IT界非常知名的博主荣誉的象征&#xff0c;博主在这个过程中也给大家贡献了很多优质内容。 在过去的几年中&#xff0c;博主们给我们博客之星活动提了很多建议&#xff0c;其中最强烈的一点就是&#…...

【新2023Q2押题JAVA】华为OD机试 - 查找树中的元素 or 查找二叉树节点

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:查找树中的元素 or 查找二叉树…...

MySQL 日志:undo log、redo log、binlog 有什么用?

目录一、bin log1.作用2.刷盘时机3.日志格式二、redo log1.为什么需要redo log2.基本概念3.作用3.刷盘时机三、undo log1.作用四、Mysql的时机顺序五、redo log 与 binlog 的两阶段提交六、总结一、bin log 1.作用 MySQL的bin log日志是用来记录MySQL中增删改时的记录日志。 …...

ETL 与 ELT的关键区别

ETL 和 ELT 之间的主要区别在于数据转换发生的时间和地点 — 这些变化可能看起来很小&#xff0c;但会产生很大的影响&#xff01; ETL 和 ELT 是数据团队引入、转换并最终向利益干系人公开数据的两种主要方式。它们是与现代云数据仓库和 ETL 工具的开发并行发展的流程。 在任…...

Thinkphp 6.0模版的杂项和表单令牌

本节课我们来学习一下模版的杂项和表单令牌的功能。 一&#xff0e;模版的杂项 1. 有时&#xff0c;我们需要输出类似模版标签或语法的数据&#xff0c;这时会被模版解析&#xff1b; 2. 此时&#xff0c;我们就使用模版的原样输出标签{literal}&#xff1b; {literal} 变量标…...

linux常问

查看当前进程 ps -l 列出与本次登录有关的进程信息&#xff1b; ps -aux 查询内存中进程信息&#xff1b; ps -aux | grep * 查询 *进程的详细信息&#xff1b; top 查看内存中进程的动态信息&#xff1b; kill -9 pid 杀死进程。...

ToBeWritten之物联网MQTT、Z-Wave等协议

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…...

C# 行为型模式之责任链模式

责任链模式&#xff1a;请求从链中的一个对象传递到下一个对象&#xff0c;直到请求被响应为止。通过这种方式在对象之间去除耦合。 用途&#xff1a;请假审批、采购审批等。 案例介绍&#xff1a;以公司采购东西为例子来实现责任链模式。公司规定&#xff0c;采购架构总价在…...

layui实现请求前添加一个加载 loading 的效果,并在请求成功后关闭

1.使用 layui 的 layer 组件来实现请求前添加一个加载 loading 的效果&#xff0c;并在请求成功后关闭。 $("#switch").click(function() {layer.confirm(确认切换至英文环境?, function(index) {var loadingIndex layer.load(1, {shade: [0.1,#fff] //0.1透明度的…...

iostat / sar 命令详解

作用 iostat主要用于监控系统设备的IO负载情况&#xff0c;根据这个可以看出当前系统的写入量和读取量&#xff0c;CPU负载和磁盘负载。 iostat属于sysstat软件包。可以用yum install sysstat 直接安装。 iostat用法 1.用法&#xff1a;iostat [选项] [<时间间隔>] […...

2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。

2023-04-06&#xff1a;拥抱Golang&#xff0c;优化FFmpeg音频编码器&#xff0c;探究encode_audio.c的内部结构。 答案2023-04-06&#xff1a; 见moonfdd/ffmpeg-go库。 这段代码是一个示例程序&#xff0c;用于将音频 PCM 数据编码为 MP2 格式的音频文件。下面是代码的详细…...

归排、计排深度理解

归并排序&#xff1a;是创建在归并操作上的一种有效的排序算法。算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用&#xff0c;且各层分治递归可以同时进行。归并排序思路简单&#xff0c;速度仅次于快速排序&#xff0c;为稳定排序算法&#…...

设计原则(单一职责原则 开放封闭原则 里氏替换原则 依赖倒置原则 接口隔离原则 迪米特法则)

设计原则单一职责原则(SRP)从三大特性角度看原则:应用的设计模式&#xff1a;开放封闭原则(OCP)从三大特性角度看原则:应用的设计模式&#xff1a;里氏替换原则(LSP)从三大特性角度看原则:应用的设计模式&#xff1a;依赖倒置原则(DIP)从三大特性角度看原则:应用的设计模式&…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...

MySQL 数据库深度剖析:事务、SQL 优化、索引与 Buffer Pool

在当今数据驱动的时代&#xff0c;数据库作为数据存储与管理的核心&#xff0c;其性能与可靠性至关重要。MySQL 作为一款广泛使用的开源数据库&#xff0c;在众多应用场景中发挥着关键作用。在这篇博客中&#xff0c;我将围绕 MySQL 数据库的核心知识展开&#xff0c;涵盖事务及…...