【数据结构】二叉树之链式结构

在这里插入图片描述
🔥博客主页 小羊失眠啦.
🎥系列专栏《C语言》 《数据结构》 《Linux》《Cpolar》
❤️感谢大家点赞👍收藏⭐评论✍️


在这里插入图片描述

文章目录

  • 一、前置说明
  • 二、二叉树的遍历
    • 2.1 前序遍历
    • 2.2 中序遍历
    • 2.3 后序遍历
    • 2.4 层序遍历
  • 三、二叉树的结点个数
    • 3.1 二叉树的总结点数
    • 3.2 二叉树的叶子结点数
    • 3.3 二叉树第k层结点数
  • 四、二叉树的高度/深度
  • 五、二叉树的查找
  • 六、二叉树的创建和销毁

一、前置说明

在学习二叉树各种各样的操作前,我们先来回顾一下二叉树的概念:

二叉树是度不超过2的树,由根结点和左右2个子树组成,每个子树也可以看作一颗二叉树,又可以拆分为根结点和左右两颗子树…

在这里插入图片描述

是不是很熟悉,一个大问题可以拆分为两个子问题,每个子问题又可以拆分为更小的子问题,这样层层拆分到不可拆分(遇到空树)的过程,不就是递归吗!因此,我们可以得出:

树是递归定义的,后续树的各种操作正是围绕着这一点进行的。

二、二叉树的遍历

我们先从最简单的操作----遍历学起。所谓二叉树遍历(Traversal)就是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个节点有且只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。二叉树的遍历分为四种:前序遍历中序遍历后序遍历层序遍历

2.1 前序遍历

前序遍历(Preorder Traversal)又称先根遍历,即先遍历根结点,再遍历左子树,最后遍历右子树。而对于子树的遍历,也服从上述规则。利用递归,我们可以很快地写出代码:

//前序遍历
void PrevOrder(BTNode* root) {//遇到空树,递归终点if (root == NULL) {printf("NULL ");return;}//对根节点进行操作(此处为打印)printf("%d ", root->val);//递归遍历左子树PrevOrder(root->left);//递归遍历右子树PrevOrder(root->right);
}

为了更好地理解这个过程,我们可以画出递归展开图如下:

在这里插入图片描述

2.2 中序遍历

中序遍历(Inorder Traversal)又称中根遍历,即先遍历左子树,再遍历根结点,最后遍历右子树。同样,子树的遍历规则也是如此。递归代码如下:

void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%d ", root->val);InOrder(root->right);
}

2.3 后序遍历

后序遍历(Inorder Traversal)又称后根遍历,即先遍历左子树,再遍历右子树,最后遍历根结点。照葫芦画瓢,递归代码如下:

void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->val);
}

2.4 层序遍历

除了上面的前中后序遍历,还可以对二叉树进行层序遍历。所谓层序遍历就是从所在二叉树的根节点出发,首先访问第1层的根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推。这样自上而下,自左向右逐层访问树的结点的过程就是层序遍历。

在这里插入图片描述

与前面三种遍历不同,层序遍历属于广度优先遍历,因此我们可以利用队列先进先出的特性,将每个结点一层一层依次入队,然后依次出队进行操作即可。具体演示及代码如下:

img

void LevelOrder(BTNode* root)
{Que q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);printf("%d ", front->val);if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);QueuePop(&q);}printf("\n");QueueDestroy(&q);
}

在这里插入图片描述

三、二叉树的结点个数

3.1 二叉树的总结点数

一颗二叉树的结点数我们可以看作是根结点+左子树结点数+右子树结点数,那左右子树的结点数又是多少呢?按照相同的方法继续拆分,层层递归直到左右子树为空树,返回空树的结点数0即可。递归代码如下:

int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

3.2 二叉树的叶子结点数

左右子树都为空的结点即是叶子结点。这里分为两种情况:左右子树都为空左右子树不都为空

  1. 当左右子树都为空时,则这颗树的叶子结点数为1(根节点)。

  2. 当左右子树不都为空,即根结点不是叶子结点时,这棵树的叶子结点数就为左子树叶子结点数+右子树叶子结点数(空树没有叶子结点)。

int TreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

3.3 二叉树第k层结点数

类似的,一颗树第k层的结点数我们可以拆分为其左子树第k-1层结点+右子树第k-1层结点。这样层层递归下去,直到k==1求树的第1层结点数时返回1(树的第1层只有根结点),而如果在递归过程中遇到空树就返回0(空树没有结点)。例如下面一颗树:

在这里插入图片描述

int TreeKLevel(BTNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1){return 1;}return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);
}

在这里插入图片描述

四、二叉树的高度/深度

树中结点的最大层次称为二叉树的高度。因此,一颗二叉树的高度我们可以看作是

1(根结点)+左右子树高度的较大值。层层递归下去直到遇到空树返回0即可,递归代码如下:

int TreeHeight(BTNode* root)
{if (root == NULL)return 0;return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

在这里插入图片描述

五、二叉树的查找

二叉树的查找本质上就是一种遍历,只不过是将之前的打印操作换为查找操作而已。我们可以使用前序遍历来进行查找,先比较根结点是否为我们要查找的结点,如果是,之间返回;如果不是,遍历左子树和右子树,返回其查找的结果;如果都找不到,返回空指针。代码如下:

// 二叉树查找值为x的结点
BTNode* TreeFind(BTNode* root, int x)
{if (root == NULL)return NULL;if (root->val == x)return root;BTNode* ret = NULL;ret = TreeFind(root->left, x);if (ret)return ret;ret = TreeFind(root->right, x);if (ret)return ret;return NULL;
}

六、二叉树的创建和销毁

最后,我们再来看看如何来创建和销毁一颗二叉树。我们前面说过:二叉树是递归定义的。有了前面的基础,二叉树的创建和销毁也就不是什么难事了。

BTNode* BuyNode(int x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");exit(-1);}node->val = x;node->left = NULL;node->right = NULL;return node;
}// 二叉树销毁
void TreeDestroy(BTNode* root)
{if (root == NULL){return;}TreeDestroy(root->left);TreeDestroy(root->right);free(root);//root = NULL;
}

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有任何问题可以在评论区留言,小羊一定认真修改,写出更好的文章~~

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在本地安装部署WinSCP,并实现公网远程本地服务器

可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器 文章目录 可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器1. 简介2. 软件下载安装:3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 …

送PDF书 | 豆瓣9.2分,超250万Python新手的选择!蟒蛇书入门到实践

在此疾速成长的科技元年,编程就像是许多人通往无限可能世界的门票。而在编程语言的明星阵容中,Python就像是那位独领风 骚的超级巨星, 以其简洁易懂的语法和强大的功能,脱颖而出,成为全球最炙手可热的编程语言之一。 …

Gitea和Jenkins安装

Gitea Gitea:https://dl.gitea.com/gitea/1.21.0/ Jenkins:https://www.jenkins.io/download/ 数据库配置 可以参考官方文档-https://docs.gitea.cn/1.20/installation/database-prep,这里以MySQL作为讲解 MySQL 在数据库实例上&#xf…

智能物流时代:快递物流信息订阅与推送API自动推送物流变更信息

引言 在当今数字化和智能化的时代,物流行业也在迅速演变,通过技术创新提高效率、提升服务质量。其中,快递物流信息订阅与推送API的自动推送功能成为推动物流领域发展的重要驱动力。本文将深入探讨这一趋势,并分析快递物流信息订阅…

完美解决:vue.js:6 TypeError: Cannot read properties of undefined (reading ‘0‘)

Vue项目出现以下报错: 原因: 在渲染的时候,不满足某个条件而报错,或者某个属性丢失或后台没传过来导致 我这里出现的原因是后台给我传递过来的数组中,其中有一条少传了一个我在渲染时需要用的属性,没让后台…

如何使用Java支付宝沙箱环境并公网调用sdk创建支付单服

Java支付宝沙箱环境支付,SDK接口远程调试【内网穿透】 1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付宝支付Java SDK,maven项目可以选择maven版本,普通java项目可以在GitHub下载,这里以maven为例 SDK下载地址:https://doc.open.alipay.com…

阻塞队列及简单实现,生产者消费者模型

文章目录 阻塞队列阻塞队列是什么生产者消费者模型阻塞队列的实现 阻塞队列 阻塞队列是什么 阻塞队列是一种特殊的队列. 也遵守 “先进先出” 的原则. 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素当队列空的时候, 继续出队列也会阻塞, 直到有其他线…

有效实施的五条教学策略

作为老师,是否曾为如何提高教学质量而苦恼?也为如何引导学生而思考?如果你正面临这些困扰,那么这篇文章将对你有帮助。为你介绍五条教学策略,帮你实施教学,提高效果。 明确教学目标 你是否知道你的教学目标…

针对操作系统漏洞的反馈方法

一、针对操作系统漏洞的反馈方法 漏洞扫描指基于漏洞数据库,通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测,发现可利用漏洞的一种安全检测(渗透攻击)行为。在进行漏洞扫描后,需先确定哪些是业务…

Go 内置运算符

一、算数运算符 1、算数运算符使用 package mainimport ("fmt" )func main(){fmt.PrintIn("103",103) //10313fmt.PrintIn("10-3",10-3) //10-37fmt.PrintIn("10*3",10*3) //10*330//除法注意:如果运算的数都是…

视频后期效果制作工具Mocha Pro 2022 Plugins mac中文版软件介绍

Mocha Pro 2022 mac是一款专业的三维摄像机反求摩卡跟踪插件,同时也是一款视频后期效果制作工具,Mocha Pro 2022下载能够给数字媒体艺术家提供强大的、直观的和创新的追踪解决方案用简化的界面、加速的工作流程以及轻松追踪和操作镜头的强大性&#xff0…

js moment时间范围拿到中间间隔时间

2023.11.27今天我学习了如何对只返回的开始时间和结束时间做处理,比如后端返回了: [time:{start:202301,end:202310}] 我们需要把中间的间隔渲染出来。 [202301,202302,202303,202304,202305,202306,202307,202308,202309,202310] 利用moment的add进…

Linux下使用Docker部署MinIO存储服务实现远程上传

📑前言 本文主要是Linux下通过Docker部署MinIO存储服务实现远程上传的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 &#…

【AD9371 AD9375 概要总结】A ...

目录 工作原理发射器 TRANSMITTER(Tx)接收器 RECEIVER (Rx)观测接收器 OBSERVATION RECEIVER (ORx)嗅探接收器 SNIFFER RECEIVER(SnRx)时钟输入 CLOCK INPUTSYNTHESIZERS合成RF PLL射…

推动企业数字化转型,如何更好地规避失败风险?

随着科技的飞速发展,数字化转型已成为企业持续发展的必然选择,然而有相关数据显示,超过80%的企业在数字化转型过程中都遭遇失败。本文将揭示企业数字化转型常见的失败原因,并探讨如何帮助企业规避转型失败风险。 一、企业数字化转…

力扣:182. 查找重复的电子邮箱(Python3)

题目: 表: Person ---------------------- | Column Name | Type | ---------------------- | id | int | | email | varchar | ---------------------- id 是该表的主键(具有唯一值的列)。 此表的每一行都包含一封电子…

飞翔的鸟小游戏

第一步是创建项目 项目名自拟 第二步创建个包名 来规范class 再创建一个包 来存储照片package game; import java.awt.*; import javax.swing.*; import javax.imageio.ImageIO; public class Bird { Image image; int x,y; int width,height; int size…

BUUCTF刷题之路--ciscn_2019_es_21

这题考察的是一个栈迁移的知识。作为入门学习栈迁移是个不可多得的好题。程序简单并且是32位的架构。保护也没有开,因此对于理解栈迁移再好不过了。看一下这题的基本信息: 栈迁移的基本原理其实就是栈的空间不够我们利用。也就是不不足以覆盖返回地址&am…

python之yaml技术(可用于写接口自动化的测试用例文件)

一.yaml介绍 yaml文件是一种配置文件类型,相比较ini,conf配置文件来说,更加的简洁,操作也更加简单,同时可以存放不同类型的数据。 yaml使用场景 配置文件 测试用例 二.yaml语法 大小写敏感 使用缩进表示层级关系…

Pytorch深度学习实战2-1:详细推导Xavier参数初始化(附Python实现)

目录 1 参数初始化2 Xavier参数初始化原理2.1 前向传播阶段2.2 反向传播阶段2.3 可视化思考 3 Python实现 1 参数初始化 参数初始化在深度学习中起着重要的作用。在神经网络中,参数初始化是指为模型中的权重和偏置项设置初始值的过程。合适的参数初始化可以帮助模型…