数据结构初阶之二叉树的详细解析

news2024/11/28 22:50:24

个人主页:点我进入主页

专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶

C语言刷题       数据结构初阶    Linux

欢迎大家点赞,评论,收藏。

一起努力,共赴大厂。

目录

1.前言 

2.二叉树各个功能代码实现

2.1二叉树结构体

2.2二叉树的前序遍历 

2.3中序遍历 

2.4后序遍历

2.5计算二叉树节点个数

2.6计算二叉树叶子节点的个数 

2.7计算二叉树的深度

2.8计算第k层的节点个数

2.9层序遍历

2.10层序遍历变式

2.11判断是否为完全二叉树

2.12二叉树内存释放

2.13树的创建

3.二叉树的性质

4.总结


1.前言 

        我在前面写过关于顺序表,栈,队列,堆的存储结构,现在我们还有一种一对多的存储结构树,在堆的博客中我写过一些树的概念,树的增删查改在我们的应用中并不实用,其中有用的是查找树,但是查找树的实现我们还没有能力去实现,树的实现可以用顺序表实现也可以用链表去实现,这次我们用链式二叉树去实现,利用顺序表实现可以看堆的内容。在这篇文章中我主要给大家带来关于二叉树的创建,树的一些性质,树的前序中序后序层序遍历,求树的节点个数,叶子节点个数,树的深度,第k层节点的个数,判断是不是完全二叉树,在这些中大部分需要用递归,我会给搭建展示部分功能的递归展开图来帮助大家理解,在学习这写内容中我建议大家可以会回忆一下递归的内容,是不是看到递归就觉得畏惧吗?其实我们只需要多去感受一下其中的思路与思想,不用过多的去畏惧递归,接下来就让我们看看其中是如何用递归去实现吧。

2.二叉树各个功能代码实现

2.1二叉树结构体

typedef struct BiTreeNode {
	int val;
	struct BiTreeNode* left, * right;
}BTNode;

结构体的内容包括结构体的内容,指向二叉树的左孩子的指针,指向二叉树的右孩子的指针。我给大家来看一下二叉树的大概的模型

2.2二叉树的前序遍历 

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

例如我们利用上面的二叉树进行模拟

我们可以根据代码展开图进行一步步实现代码实现的过程,最好我们自己去画一画代码展开图这样对于我们去了解递归会有非常好的作用。

2.3中序遍历 

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

我们的代码展开图如下

 我们可以看到我们的中序遍历代码和前序遍历代码大致相同,相差的只是代码的顺序,我们可以将大部分二叉树的递归可以表示为根节点,左孩子右孩子,左子树右子树和根节点,左孩子右孩子这两种,这非常有用是一种分治的思想。

2.4后序遍历

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

在这里我们不给代码展开图了,大家可以自己去画一画代码展开图。

2.5计算二叉树节点个数

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

我们想到二叉树的递归内容可以表示为根节点,左孩子右孩子,左子树右子树或根节点,左孩子右孩子,我们可以看成根节点,左子树右子树,当根节点为空时我们返回0,我们分为左子树和右子树所以我们返回BTreeSize(root->left) + BTreeSize(root->right) + 1进行递归,我们的递归展开图可以画为

2.6计算二叉树叶子节点的个数 

        我们可以根据根据根节点,左子树右子树进行分治,当我们的根节点为空时返回0,当左孩子和右孩子为空是叶子节点返回1,对于左子树和右子树我们进行递归。

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

递归展开图和上面的相似,大家可以自己去画一画。

2.7计算二叉树的深度

 我们可以根据根据根节点,左子树右子树进行分治,当根节点为空时返回0,然后进行递归。

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

2.8计算第k层的节点个数

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

当我们的根节点是空时我们返回0,当我们的k变成1时我们返回1,根据左子树右子树进行分治每次都让k-1。

2.9层序遍历

void Levelorder(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	if (root)
	{
		QueuePush(&queue, root);
	}
	while (!QueueEmpty(&queue))
	{
		BTNode* prev = top(&queue) ;
		QueuePop(&queue);
		if (prev->left)
			QueuePush(&queue, prev->left);
		if (prev->right)
			QueuePush(&queue, prev->right);
		printf("%d ", prev->val);
	}
}

在层序遍历中我们利用队列进行存储,先将非空的根节点进行插入,进行循环队列不为空进行循环,利用一个二叉树的指针指向队头的元素(队列里的元素存的是二叉树的节点时结构体的指针所以我们可以用二叉树的指针进行指向),然后出队,入指针的非空左孩子右孩子,每次打印指针对应的值。

2.10层序遍历变式

        如果我们想每层打印时打印完每次会输出一个换行,这时候我们应该如何作呢?我们首先想到的是再搞一个队列,存放第一个队列元素是第几层,但是我们c语言去实现队列是非常麻烦的,连结构体都需要我们去重新设定,那我们应该如何去做呢?在我们的层序遍历中你有没有注意到我们的队列中总是存在全部的一层元素或者一层与下一层的元素这两种情况,什么时候会出现只有一层的元素呢?那就是上一层全部出队了,这便是我们的突破点,当我们将非空根节点入队后我们引入一个变量存放队中的元素的个数然后进入循环,此时这个变量就是一层元素的个数,我们每次出一个元素就让这个变量减1,这也就是我们的循环条件,循环结束后我们重新计算这个变量的值,这时候队中还是只有一层全部的节点,此时变量的值就是队中元素的个数。

2.11判断是否为完全二叉树

bool BinaryTreeComplete(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	if (root)
		QueuePush(&queue, root);
	while (top(&queue))
	{
		BiTreeNode* front = top(&queue);
		QueuePop(&queue);
		QueuePush(&queue, front->left);
		QueuePush(&queue, front->right);
	}
	return QueueEmpty(&queue);

}

首先我们需要了解完全二叉树的性质,他和满二叉树类似,但是序号必须和满二叉树相同,这时候我们采用层序遍历的方式进行判断,我们将非空根节点入队,判断条件是队头元素不是空,每个节点入队当我们遇到空节点时我们判断队是不是都是空节点,如果是就是完全二叉树,为什么这样可以呢?当我们入队后一旦想出某一层时这一层的全部节点就会入队,然后进行判断就可以了。

2.12二叉树内存释放

二叉树内存前序中序后序都可以实现,但是我们如何做才能让这个操作根号的实现呢?我们想类似于前中后序遍历的样子进行,这时候你会发现,利用前序和中序遍历会提前将节点释放,以至于我们不能找到其他的节点,但是我们采用后序遍历就完美的避免了这个问题,所以我们在释放二叉树时我们经常采用后序遍历的方式。

void BTNodeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BTNodeDestory(root->left);
	BTNodeDestory(root->right);
	free(root);
}

2.13树的创建

BiTree* BiTreeCreate(BiTree* bt)
{
	bt = (BiTree*)malloc(sizeof(BiTree));
	char ch;
	scanf("%c", &ch);
	if (ch != '#')
	{
		bt->data = ch;
		bt->lchild = BiTreeCreate(bt);
		bt->rchild = BiTreeCreate(bt);
	}
	else
		bt = NULL;
	return bt;
}

3.二叉树的性质

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 .
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 = +1
4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2
为底,n+1为对数)
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对
于序号为i的结点有:
1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

4.总结

        事实上我们二叉树的内容并不是很难,更多的需要我们去理解,这就需要我们多去感受一线二叉树的实现,最后希望大家可以来三连。到这里我们树的内容就解决了三分之二,其余的三分之一我会将以C++的形式来为大家讲解,不过可能会等上一段时间了。在下一篇文章中我会给大家带来一些二叉树的题目,欢迎大家持续关注。

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

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

相关文章

智能优化算法应用:基于猎食者算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于猎食者算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于猎食者算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.猎食者算法4.实验参数设定5.算法结果6.参考文献7.…

C# WebSocket简单使用

文章目录 前言Fleck调试工具初始化简单使用 前言 最近接到了一个需求&#xff0c;需要网页实现上位机的功能。那就对数据传输的实时性要求很高。那就只能用WebSocket了。这里简单说一下我的WebSocket如何搭建 Fleck C# WebSocket(Fleck) 客户端:html Winfrom Fleck Github官网…

lorenz相图

观察Lorenz在各个不同维度上的相图。 lorenz_demo(50) function xdot g(t,x) xdot zeros(3,1); sig 10.0; rho 28.0; bet 8.0/3.0; xdot(1) sig*(x(2)-x(1)); xdot(2) rho*x(1)-x(2)-x(1)*x(3); xdot(3) x(1)*x(2)-bet*x(3); endfunction lorenz_demo(time) [t,x] ode…

软考高项第四版五组十域表+ITTO背诵笔记及助记

基于第四版做的笔记&#xff0c;助记是自己编的 还是得靠理解记忆&#xff0c;下面是文档&#xff0c;也用anki制作了记忆卡片&#xff0c;需要的可以自行导入卡包

谷歌推出功能最强大的大语言模型Gemini;大规模语言模型:从理论到实践

&#x1f989; AI新闻 &#x1f680; 谷歌推出功能最强大的大语言模型Gemini 摘要&#xff1a;谷歌正式推出其迄今为止功能最强大、最通用的大语言模型Gemini。Gemini在许多测试中表现出了最先进的性能&#xff0c;在大部分基准测试中击败了OpenAI的GPT-4。谷歌发布了三种不同…

直播录屏软件哪个好?这3款软件请你收好

随着直播文化的兴起&#xff0c;越来越多的人开始尝试通过直播平台分享自己的经验、技能和生活。在这个过程中&#xff0c;选择一款优秀的直播录屏软件变得至关重要&#xff0c;可是直播录屏软件哪个好呢&#xff1f;本文将深入介绍3款备受欢迎的直播录屏软件。通过详细的步骤指…

SQL语言重温

数据库语言重温 笔记背景SQL教程一些最重要的 SQL 命令SQL WHERE 子句SQL AND & OR 运算符SQL ORDER BY 关键字 笔记背景 由于工作需要&#xff0c;现重温简单SQL语言&#xff0c;笔记记录如下。 SQL教程 SQL&#xff08;Structured Query Language:结构化查询语言&…

[Realtek sdk-3.4.14b] RTL8197FH-VG+RTL8812FR WiFi黑名单及剔除已连接终端功能实现

sdk说明 ** Gateway/AP firmware v3.4.14b – Aug 26, 2019**  Wireless LAN driver changes as:  Refine WiFi Stability and Performance  Add 8812F MU-MIMO  Add 97G/8812F multiple mac-clone  Add 97G 2T3R antenna diversity  Fix 97G/8812F/8814B MP issu…

数字文化大观:TikTok影响下的全球文娱

在数字时代的大潮中&#xff0c;社交媒体平台正成为全球文娱产业的重要引擎之一。而TikTok&#xff0c;作为一款以短视频为特色的社交应用&#xff0c;正深刻地改变着全球文娱的面貌。 本文将深入研究TikTok对全球文娱的影响&#xff0c;探讨数字文化在这一平台的催化下如何迅…

销售技巧培训课程内容如何设计才能更好地落地

销售技巧培训课程内容如何设计才能更好地落地 在当今竞争激烈的市场环境中&#xff0c;销售人员的角色和作用越来越重要&#xff0c;是公司业绩来源的核心&#xff0c;也是公司能否在激烈竞争的市场中立于不败之地的关键。 因此&#xff0c;对销售人员进行有效的销售技巧培训&a…

redis中使用事务

事务是指一个执行过程&#xff0c;要么全部执行成功&#xff0c;要么失败什么都不改变。不会存在一部分成功一部分失败的情况&#xff0c;也就是事务的ACID四大特性&#xff08;原子性、一致性、隔离性、持久性&#xff09;。但是redis中的事务并不是严格意义上的事务&#xff…

Java基础-代码块及其细节

代码块概念&#xff1a; 注意调用时机 好处与使用场景 将构造器的冗余部分提取到代码块 每个构造器执行时都会先执行代码块 静态代码块与普通代码块的区别 注意&#xff1a;创建对象实例时&#xff0c;静态代码块只会被调用一次 例子 public Class DD{static{//打印"…

【Linux】stat命令使用

stat命令 stat命令用于显示文件的状态信息。stat命令的输出信息比ls命令的输出信息要更详细。 著者 由Michael Meskes撰写。 stat命令 -Linux手册页 语法 stat [文件或目录] 命令选项及作用 执行令 &#xff1a; stat --help 执行命令结果 参数 -L、 --dereference 跟…

imutils库介绍及安装学习

目录 介绍 本机环境 安装 常用函数 使用方法 图像平移 图像缩放 图像旋转 骨架提取 通道转换 OPenCV版本的检测 综合测试 目录 介绍 本机环境 安装 常用函数 使用方法 图像平移 图像缩放 图像旋转 骨架提取 通道转换 OPenCV版本的检测 介绍 imutils 是一…

CSM2433 一款集成2.4G+125K 和8位RISC 的SOC芯片

CSM2433是一款集成2.4GHz频段发射器、125KHz接收器和8位RISC&#xff08;精简指令集&#xff09;MCU的SOC芯片。 无线收发器特性&#xff1a; 发射工作在 2.4GHz ISM 频段 发射兼容 BLE 4.2 接收工作在 15KHz-150KHz 内置 32 次可编程 NVM 存储器 3.3V 编程电压 集成低电…

Android笔记(十七):PendingIntent简介

PendingIntent翻译成中文为“待定意图”&#xff0c;这个翻译很好地表示了它的涵义。PendingIntent描述了封装Intent意图以及该意图要执行的目标操作。PendingIntent封装Intent的目标行为的执行是必须满足一定条件&#xff0c;只有条件满足&#xff0c;才会触发意图的目标操作。…

【每日一题】—— D. Jumping Through Segments(Codeforces Round 913 (Div. 3))(二分)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

配置端口安全示例

组网需求 如图1所示&#xff0c;用户PC1、PC2、PC3通过接入设备连接公司网络。为了提高用户接入的安全性&#xff0c;将接入设备Switch的接口使能端口安全功能&#xff0c;并且设置接口学习MAC地址数的上限为接入用户数&#xff0c;这样其他外来人员使用自己带来的PC无法访问公…

【MATLAB源码-第96期】基于simulink的光伏逆变器仿真,光伏,boost,逆变器(IGBT)。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 光伏单元&#xff08;PV Cell&#xff09; 工作原理&#xff1a;光伏单元通过光电效应将太阳光转换为直流电。它们的输出取决于光照强度、单元温度和负载条件。Simulink建模&#xff1a;在Simulink中&#xff0c;光伏单元…

mysql的组合查询

mysql的组合查询 1、mysql的内连接查询 在 MySQL 中&#xff0c;内连接&#xff08;INNER JOIN&#xff09;是一种根据两个或多个表之间的匹配条件&#xff0c;将多个表中的数据进行联接的操作。内连接只返回符合联接条件的行&#xff0c;而不会返回未匹配的行。 内连接的语…