数据结构_链式二叉树(Chained binary tree)基础

✨✨所属专栏:数据结构✨✨

✨✨作者主页:嶔某✨✨

 二叉树的遍历

前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{	
		printf("# ");
		return;
	}
	printf("%c ",root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	BinaryTreePrevOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
	printf("%c ", root->_data);
}

层序遍历

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

这里与前、中、后序遍历不同的是:层序遍历用的迭代而非递归。创建一个队列,将整个树的根节点入队,之后再将根节点的左右节点入队。让上一层节点带动下一层,父节点将子女节点带入队,之后将父节点拿出队列,这样就实现了层序遍历。

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	assert(root);
	Queue q;
	QueueInit(&q);
	QueuePush(&q,root);
	
	while (QueueSize(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		printf("%c ", front->_data);

		if (front->_left)
			QueuePush(&q,front->_left);
		if(front->_right)
			QueuePush(&q,front->_right);
	}
}

 其他函数

通过前序遍历数组创建二叉树

 判断下标为i的字符是否为'#',如果不为'#'那就新malloc一个节点将数据放进去,新节点的左右节点分别再递归赋值。

BTNode* BinaryTreeCreate(BTDataType* a,int* pi)
{
	if (a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* new = (BTNode*)malloc(sizeof(BTNode));
	if (new == NULL)
	{
		perror("malloc is fail");
		return NULL;
	}
	new->_data = a[(*pi)++];
	new->_left = BinaryTreeCreate(a, pi);
	new->_right = BinaryTreeCreate(a, pi);
	return new;
}

销毁二叉树

如果当前节点为空那么就释放,如果当前节点不为空,那么就先递归释放左右子树,左右子树释放后再将根节点释放并置空。

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		free(*root);
		return;
	}
	BinaryTreeDestory(&(*root)->_left);
	BinaryTreeDestory(&(*root)->_right);
	free(*root);
	*root = NULL;
}

二叉树节点个数

如果当前节点为空返回0,如果当前节点不为空返回其左右子树的节点个数+1。

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->_left)
         + BinaryTreeSize(root->_right) + 1;
}

二叉树叶子节点个数

如果节点的左右节点都为空返回1,否则返回左右子树的叶子节点个数。

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->_left == NULL && root->_right == NULL)
		return 1;
	return BinaryTreeLeafSize(root->_left)
         + BinaryTreeLeafSize(root->_right);
}

二叉树第k层节点个数

第k层节点的个数,可以看作第一层的左右节点的第k-1层节点个数,因此当k == 1时此层就是要计算再内的节点。

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->_left, k - 1)
		 + BinaryTreeLevelKSize(root->_right, k - 1);
}

二叉树查找值为x的节点

采取前序遍历,如果根节点的值等于x,返回root,否则先判断左子树有无符合节点,若有返回对应的节点,反之返回另一个子树的对应节点,若左右字数都没有对应节点,最终将返回空

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	BTNode* ret1 = BinaryTreeFind(root->_left, x);
	if (ret1 != NULL)
		return ret1;
	return BinaryTreeFind(root->_right, x);	
}

判断二叉树是否为完全二叉树

建立一个队列,和层序遍历一样,当遇到空节点时,跳出循环,开始判断。如果再空节点的后面还有非空节点,那么这棵树就不是完全二叉树。反之此树空节点之后的所有的节点都为空,那么此树为完全二叉树。

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	assert(root);
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);

	while (QueueSize(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front == NULL)
			break;
		
		QueuePush(&q, front->_left);
		QueuePush(&q, front->_right);
	}
	while (QueueSize(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			Destory(&q);
			return false;
		}
	}
	return true;
}

本期博客到这里就结束了,如果有什么错误,欢迎指出,如果对你有帮助,请点个赞,谢谢!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】求第n个斐波那契数

问题与前言 输入n,输出第n个斐波那契数 例如: 输入:5 输出:5 输入:10, 输出:55 输入:2, 输出:1 斐波那契数列(Fibonacci sequence&#xf…

二叉树OJ题目

一.二叉树第k层结点个数 有这样的一个思路:我既然要求第k层的结点个数,我肯定是要用到递归,那么当我在递归到第k层的时候我就开始判断,这一层是不是我所需要的那一层,如果是,就计数有几个节点,…

从零开始写 Docker(十五)---实现 mydocker run -e 支持环境变量传递

本文为从零开始写 Docker 系列第十五篇,实现 mydocker run -e, 支持在启动容器时指定环境变量,让容器内运行的程序可以使用外部传递的环境变量。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现…

【开发 | 环境配置】解决 VSCode 编写 eBPF 程序找不到头文件

问题描述: 在使用 vscode 编写 eBPF 程序时,如果不做一些头文件定位的操作,默认情况下头文件总是带有“红色下划线”,并且大部分的变量不会有提示与补全。 在编写代码文件较小时(或者功能需求小时)并不会…

42-2 应急响应之计划任务排查

一、进程排查 进程排查是指通过分析系统中正在运行的进程,以识别和处理恶意程序或异常行为。在Windows和Linux系统中,进程是操作系统的基本单位,因此对于发现和处理恶意软件或异常活动至关重要。恶意程序通常会以进程的形式在系统中运行,执行各种恶意操作,比如窃取信息、破…

CSAPP(datalab)解析

howManyBits /* howManyBits - 返回用二进制补码表示x所需的最小位数* 示例: howManyBits(12) 5* howManyBits(298) 10* howManyBits(-5) 4* howManyBits(0) 1* howManyBits(-1) 1* howManyBits(0x80000000) …

零部件销售|基于SSM+vue的轻型卡车零部件销售平台系统的设计与实现(源码+数据库+文档)

轻型卡车零部件销售平台 目录 基于SSM+vue的轻型卡车零部件销售平台系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1 系统功能模块 2 管理员功能模块 3 用户后台功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题…

Leetcode—2769. 找出最大的可达成数字【简单】

2024每日刷题(139) Leetcode—2769. 找出最大的可达成数字 实现代码 class Solution { public:int theMaximumAchievableX(int num, int t) {return num t * 2;} };运行结果 之后我会持续更新,如果喜欢我的文章,请记得一键三连…

Unity Assembly Definition Dotween 引用

原理: 具体Unity程序集原理用法,暂时留坑,不介绍了,相信有很多人也写过了 这里简单放个官方API链接 https://docs.unity3d.com/cn/current/Manual/ScriptCompilationAssemblyDefinitionFiles.html 现象 :Dotween引用…

二十七篇:未来掌控:嵌入式系统的革命性进展

未来掌控:嵌入式系统的革命性进展 1. 引言:嵌入式系统的重要性及其在未来科技中的角色 在当今这个数字化迅速发展的时代,嵌入式系统已成为推动现代科技进步的基石。从智能手机到智能家居,从自动驾驶汽车到复杂的工业控制系统&…

四元数学习总结(1)

导语:相比矩阵,用四元数处理3D旋转的优势是毋庸置疑的,但由于概念复杂,难于理解,一直令我摸不着头脑。最近学习更是发现在机器人、无人机、SLAM等先进领域,四元数被当成实数、整数这样的基础,所…

详解CSS(一)

目录 1.CSS是什么 2.基本语法规范 3.引入方式 3.1内部样式表 3.2行内样式表 3.3外部样式表 4.选择器 4.1基础选择器 4.1.1标签选择器 4.1.2类选择器 4.1.3id选择器 4.1.4通配符选择器 4.2复合选择器 4.2.1后代选择器 4.2.2子选择器 4.2.3并集选择器 4.2.4伪类选择…

虚拟化技术[3]之网络虚拟化

网络虚拟化 网络虚拟化简介核心层网络虚拟化接入层网络虚拟化虚拟机网络虚拟化案例: VMware网络虚拟化技术虚拟网络接口卡虚拟交换机vSwitch分布式交换机端口组VLAN 网络虚拟化简介 传统的数据中心:服务器之间操作系统和上层软件异构、接口与数据格式不统一&#x…

@JsonFormat注解出现日期序列化以及反序列化问题(日期比实际日期少一天)

文章目录 前言一、场景如下所示二、问题分析三、JsonFormat注解是什么以下是 JsonFormat 注解的一些常用属性: 四、解决问题解决方式:只需要指定对应的时区就好效果如下: 五、JsonFormat 注解时出现日期问题总结 前言 在一次的偶然机会下发现…

二进制中1的个数c++

题目描述 计算鸭给定一个十进制非负整数 NN&#xff0c;求其对应 22 进制数中 11 的个数。 输入 输入包含一行&#xff0c;包含一个非负整数 NN。(N < 10^9) 输出 输出一行&#xff0c;包含一个整数&#xff0c;表示 NN 的 22 进制表示中 11 的个数。 样例输入 100 …

【算法题】520 钻石争霸赛 2024 全解析

都是自己写的代码&#xff0c;发现自己的问题是做题速度还是不够快 520-1 爱之恒久远 在 520 这个特殊的日子里&#xff0c;请你直接在屏幕上输出&#xff1a;Forever and always。 输入格式&#xff1a; 本题没有输入。 输出格式&#xff1a; 在一行中输出 Forever and always…

Ubuntu 如何根据NVIDIA显卡型号确定对应的显卡驱动版本并安装

目录 一、查询推荐安装的驱动版本 二、安装推荐版本的驱动 1. 通过终端安装&#xff0c;只安装 nvidia 驱动&#xff08;亲测可用&#xff01;&#xff09; 2. 通过 software & Updates 安装&#xff0c;安装 nvidia 驱动。 三、查询能安装的最新的显卡驱动版本 1. 方…

洛谷P3574 [POI2014] FAR-FarmCraft(树形dp)

洛谷 P 3574 [ P O I 2014 ] F A R − F a r m C r a f t &#xff08;树形 d p &#xff09; \Huge{洛谷P3574 [POI2014] FAR-FarmCraft&#xff08;树形dp&#xff09;} 洛谷P3574[POI2014]FAR−FarmCraft&#xff08;树形dp&#xff09; 文章目录 题意题目说明 思路标程 题目…

『Stable Diffusion 』AI绘画,不会写提示词怎么办?

提示词 有没有想过&#xff0c;为什么你用 SD 生成的猫是长这样的。 而其他人可以生成这样的猫。 虽然生成的都是猫&#xff0c;但猫与猫之间还是有差距的。 如果你的提示词只是“cat”&#xff0c;那大概率就会出现本文第一张图的那个效果。而如果你加上一些形容词&#xff…