【数据结构】——二叉树--链式结构

article/2025/6/24 11:43:35

一、实现链式结构二叉树

二叉树的链式结构,那么从名字上我们就知道我们这个二叉树的底层是使用链表来实现的,前面我们的二叉树是通过数组来实现的,那么在其是完全二叉树的情况下,此时我们使用数组来实现就会使得其空间浪费较少,如果我们的普通的二叉树也使用数组来实现的话,那么其造成的空间浪费是非常大的。

使用链表来实现二叉树,其适用于所有的二叉树。

使用链式结构实现二叉树的方法为:链表中每个结点由三个部分组成,数据域、左孩子指针、右孩子指针。

其结构如下:

那么我们有了这个链式二叉树的结构后,那么我们要如何来实现链式结构二叉树呢?

那么我们首先就是创建二叉树的结点。

1、创建二叉树结点

 结点的开辟和我们的链表是一样的,我们开辟的时候,要传的参数就是我们这个结点要存储的数据,然后我们这个结点通过二叉树结点指针返回即可 ,我们在创建的时候吗,别忘了对其初始化:

2、二叉树的遍历

二叉树的遍历分为三种方式:

1、前序遍历:先遍历根结点,然后是左结点,然后是右结点--(根左右)

如上的二叉树的前序遍历为:

A->B->D->NULL->NULL->NULL->C->E->NULL->NULL->F->NULL->NULL

2、中序遍历:先遍历左结点,然后是根结点,然后到右结点--(左根右)

如上的二叉树的中序遍历为:

NULL->D->NULL->B->NULL->A->NULL->E->NULL->C->NULL->F->NULL

3、后序遍历:先遍历左结点,然后遍历右结点,然后是根结点--(左右根)

如上的二叉树的后序遍历为:

NULL->NULL->D->NULL->B->NULL->NULL->E->F->C->A

那么我们要如何在代码中实现呢?

我们以前序遍历为例进行详细讲解:

首先我们不论是上面遍历,我们都需要这个二叉树的入口,那么我们的入口就是我们的根结点,所以我们的函数参数就是为树结点指针。

然后我们首先要进行判空,如果是空,那么我们就打印一个NULL,然后我们就终止这个函数。

如果不为空,那么我们就先将根结点的数据打印,然后我们去遍历左孩子,这是因为我们的前序遍历的顺序是根->左->右,那么我们就在这个函数中,递归调用,不过此时我们传入的参数就是根结点的左孩子了,那么其进入到左孩子后,一样还是重复的上面的操作,直到其遍历完成,然后左子树的遍历完成,那么我们就可以进入到根节点的右子树。其进入到右边子树后,还是按照根左右的顺序进行遍历即可,那么此时就可以使用我们的函数递归来实现:

其实际图解如下:

其函数栈帧如下:

 代码如下:

 那么我们的中序遍历,又是如何来遍历的呢?我们的中序遍历的顺序为左根右,那么我们可以这样,我们进入到函数,首先还是一样,先进行判空,如果为空就打印一个NULL,然后我们就递归到这个结点的左孩子,这是,然后其就进入到递归中,直到其一直递归到其左孩子是空的,那么此时就可以打印个NULL,然后就可以打印我们的根结点的值了,然后就到我们的右边孩子,进入到右边孩子后,我们这个函数还是会按照中序遍历的顺序,先去找其左孩子。

函数如下:

 同理我们的后序遍历也是如此,按照其顺序--左右根进行递归,那么我们就先递归左孩子,然后递归右孩子,然后最后打印根结点的值。

代码如下:

 上面就是链式结构二叉树的三种遍历方式。

3、链式结构二叉树的插入

我们的链式结构的二叉树的插入,那么我们的入口还是树的根结点,但是其如果为空,那么此时就使其为根结点即可,然后,如果其不为空的话,那么我们要如何进行插入呢?

我们用上面的树来举例,比如我们现在要插入的树是8,那么我们的入口是根结点,那么我们将其和当前的根结点进行比较,如果比其大,那么我们就将这个数据往其左结点处走,如果这个左结点无数据,那么就直接使其为左结点,即这个要插入的结点为这个函数的左子树的根结点,那么此时我们发现当其是大于根结点的值的时候,那么我们就让第一层的根结点的左孩子指向这个要插入的结点。那么同理,当其为小于的时候,那么我们就使其指向右孩子的指针指向递归函数,函数的参数为第一层函数的右孩子。

代码如下:

不过上面的话,对于二叉搜索树其可能不允许有重复的值,所以我们上面的代码只提供链式二叉树的数据插入的思路,仅供参考。

4、求二叉树的结点个数

 我们的二叉树求结点个数,没办法像链表那样进行遍历求,那么我们是否也可以和上面一样,使用函数的递归来求呢?

我们使用一个树来分析一下:

 和上面一样,我们从根结点为入口,然后我们递归的话,也是分为左右子树进行递归,那么我们递归结束的条件是什么呢?其实就是这个结点是空的时候,那么说明其不是结点,那么此时就结束递归即可,回到上一层递归,那么如果其不为空,那么就说明其是一个结点,那么我们的结点数就+1,那么我们的递归就可以返回一个1,还有其左右孩子的递归。

上面进行加1的原因是我们的根结点。 

5、求叶子结点个数

 前面我们讲过了,叶子结点就是其没有后继,即其指向左右孩子的指针都是为NULL的,那么我们这个可以作为一个条件,如果满足那么就为一个叶子结点,那么我们还是和上面一样进行递归其左右子树,如果其满足左右子孩子都是NULL,那么就返回1,如果其参数为NULL那么就返回0。

代码如下:

6、求第K层的结点个数

 首先我们直到的是,如果树不为空,那么我们的第一层的结点个数为1,然后就是我们的第K层的结点个数=左子树的K-1层的结点个数+右子树的第K-1的结点个数。

那么我们可以使用函数的递归,使得k变成1的时候返回1,到空的时候也要终止递归。

代码如下:

7、求二叉树的高度

 我们定义根节点的为第一层,然后我们知道,我们的二叉树的高度是左右子树中最大的一个,所以我们还是会想到使用递归左右子树的方法来进行,我们会很容易想到一个结束的条件,为空的时候返回0,然后就是我们要比较左右子树的高度,然后将大的值返回,且不要忘记+1,所以我们可以递归左右子树,分别找出左右子树的最大值,然后再进行比较。

代码如下:

8、二叉树查找值x的结点 

那么我们就需要进行遍历二叉树,那么我们可以先遍历左子树,然后遍历右子树,如果在左子树没找到,那么我们再从右子树进行查找,如果没找到那么就返NULL,反之找到就返回这个结点的地址,然后如果是空树,那么就返回NULL。

代码如下:

9、链式结构二叉树的销毁 

我们的销毁,那么我们还是需要遍历二叉树的每个结点,然后一个一个的进行内存释放,那么我们还是一样,对二叉树进行左右子树递归,然后当其不为空的时候就释放,为空的时候就终止函数。

可以发现我们销毁函数传递的是一个二级指针,这是因为我们要对一个指针进行修改,所以要使用地址传递才可以改变其实参的值。 

二、二叉树的层序遍历

 我们前面学习了二叉树的三种遍历方式,不过其是从左右子树来进行遍历,我们是否可以按照从上到下,从左到右的顺序实现二叉树的遍历呢?

要实现层序遍历,我们要借助前面学习的一个数据结构--队列。实现思路如下:

我们创建一个队列结构,其存储的是二叉树结构体,然后我们函数先将二叉树的根结点存储的数据入队,然后在进入一个循环,判断当前的队列是否为空,如果不为空,那么我们就入循环,此时我们打印队头的元素,然后将队头的元素出队,然后我们判断其是否有左孩子,如果有,那么就将其入队,然后再判断其是否有右边孩子,有的话也入队。如此反复。

代码如下:

三、判断是否完全二叉树 

我们前面讲到的,完全二叉树,其除了最后一层外,其他的层次的结点都要满,然后其最后一层的结点要从左到右排序,不可以中间有空的。

那么我们可以使用我们上面的层序遍历,当我们遍历到NULL的时候,那么我们要是往后还会找到有效的结点,那么我们的这个二叉树就不是完全二叉树。

代码如下:


http://www.hkcw.cn/article/BJTVFHGxJk.shtml

相关文章

netty中的EventLoop原理解析

一起来学netty 1. EventLoop的基本概念2. EventLoop的核心组件3. EventLoop的工作流程4. EventLoop与Channel的关系5. EventLoop的实现类6. EventLoop的线程模型7. EventLoop的优点8. EventLoop的注意事项9. 示例代码10.异步编程模型解析异步编程的定义异步编程的核心特点异步编…

使用Java实现简单的计算机案例

第一个案例我决定做一个简单的“简易计算器”,来开启编程之旅。为什么我会选择这个案例来作为第一个Java案例呢?大家可别小看这个小小的计算器,它既简单又实用。通过这个案例,大家可以学会或着练习如何处理用户输入、如何实现基本…

流媒体基础分析:延迟分析与安全性保障

在流媒体传输过程中,延迟和安全性是两个至关重要的方面。它们直接影响着用户的观看体验和内容的版权保护。本文将深入分析延迟的来源与追赶技术,并探讨流媒体传输的安全性保障手段。 1. 延迟分析 1.1 延迟说明 延迟是流媒体传输中不可避免的问题&#…

S32K3 工具篇9:如何在无源码情况下灵活调试elf文件

S32K3 工具篇9:如何在无源码情况下灵活调试elf文件 一,文档简介二, 功能实现2.1 代码工具准备2.2 elf修改功能实现:Fun2功能跳过2.2.1 PC越过Fun22.2.2 Fun2替换为nop 2.3 elf修改功能实现:Fun4替换Fun2入口2.3.1 link…

树莓派PWM控制LED灯

目录 一、什么是PWM二、树莓派引脚图三、命令行控制LED灯四、PWM控制LED呼吸灯 一、什么是PWM PWM(Pulse Width Modulation,脉冲宽度调制)是一种通过调节数字信号的占空比(Duty Cycle)来模拟模拟信号的技术。它通过快…

第十四章 MQTT订阅

系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…

六.MySQL增删查改

CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除) 一.增 insert 1.单行数据 全列插入 语法特点:不指定字段名,按表结构字段顺序依次提供所有值。 注意:字段顺序必须与表定义一…

TKernel模块--自定义RTTI,对象句柄,引用计数

TKernel模块–RTTI,对象句柄,引用计数 1.DEFINE_STANDARD_HANDLE(x1, x2) #define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient)其中: #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1…

关于TongWeb数据源兼容mysql驱动的注意事项

问题现象: TongWeb数据源在采用mysql驱动的国产数据库时,因数据库慢报超时为数据源配置参数的 validation-query-timeout值5秒,而不是期望的maxwait、connectiontimeout值。 The last packet successfully received from the server was 5,0…

CSS专题之水平垂直居中

前言 石匠敲击石头的第 16 次 在日常开发中,经常会遇到水平垂直居中的布局,虽然现在基本上都用 Flex 可以轻松实现,但是在某些无法使用 Flex 的情况下,又应该如何让元素水平垂直居中呢?这也是一道面试的必考题&#xf…

(新)MQ高级-MQ的可靠性

消息到达MQ以后,如果MQ不能及时保存,也会导致消息丢失,所以MQ的可靠性也非常重要。 一、数据持久化 为了提升性能,默认情况下MQ的数据都是在内存存储的临时数据,重启后就会消失。为了保证数据的可靠性,必须…

Microsoft Word使用技巧分享(本科毕业论文版)

小铃铛最近终于完成了毕业答辩后空闲下来了,但是由于学校没有给出准确地参考模板,相信诸位朋友们也在调整排版时感到头疼,接下来小铃铛就自己使用到的一些排版技巧分享给大家。 注:以下某些设置是根据哈尔滨工业大学(威…

Linux 基础IO(上)

目录 前言 重谈文件 文件操作 1.打开和关闭 2.对文件打开之后操作 理解文件fd 1.文件fd的分配规则与重定向 2.理解shell中的重定向 3.关于Linux下一切皆文件 关于缓冲区 1.为什么要有缓冲区 2.缓冲区刷新策略的问题 3.缓冲区的位置 前言 本篇到了我们linux中的文件…

单板机8088C语言计划

计划将原来用汇编写的小程序,用C语言重新写一遍 计划2个月能完成 然后再试试,能不能用C写一下固件BootLoad 和一个类似Dos时代的Debug调试器

C++11 语法特性一文详解

文章目录 1. C11 的发展史2. 列表初始化2.1 C98 中使用 {} 的初始化2.2 C11 中使用 {} 进行初始化2.3 std::initializer_list (初始化列表) 3. 右值引用与移动语义3.1 左值与右值3.1.1 右值分类 3.2 左值引用与右值引用3.2.1 const 左值引用为什么可以绑…

linux基础

参考视频 文章目录 1.网络的三种链接方式2. 目录结构详解3. 远程登陆和远程文件传输4. vi和vim4.1 vi和vim的三种模式4.2 vim快捷键 5. 关机重启和登录注销5.1 关机重启5.2 登录注销 6. 用户管理6.1 添加和删除用户6.2 用户信息6.3 用户组 7. 实用指令7.1 运行级别7.2 找回root…

【MLLM】多模态LLM 2025上半年技术发展(Better、Faster、Stronger)

note 文章目录 note一、新模型趋势任意模态模型推理模型小巧但功能强大的模型专家混合解码器视觉-语言-行动模型 VLA 二、特殊能力视觉语言模型中的目标检测、分割和计数多模态安全模型多模态RAG:检索器和重排器 三、多模态代理四、视频语言模型五、视觉语言模型的新…

python从零开始实现四极场离子轨迹仿真——框架

本篇将主要讲解程序的框架部分。 该程序主要分为三个部分,首先是初始化部分,主要为设置离子质荷比、初始位置、速度。 其次为求解轨迹部分,通过离子位置获取对应位置的电场,并经由空间电荷效应修改电场后,通过数值求解…

YOLO系列中的C3模块解析2025.5.31

YOLO系列中的 C3模块 是YOLOv5引入的核心组件之一,其设计目标是通过轻量化结构和高效特征提取提升模型性能。以下是C3模块的详细解析: 一、C3模块的网络层级结构 C3模块(Cross Stage Partial Network with 3 convolutions)结合了…

在Cesium中通过geojson和3d tiles分别加载楼宇白膜

一、geojson渲染楼宇白膜&#xff08;不推荐&#xff09; 如果你没有3dtiles文件来加载白膜&#xff0c;只有geojson加载白膜可以通过GeoJsonDataSource来加载白膜&#xff0c;json格式如下。 实现代码如下 <template><div id"cesium_container"></…