链式二叉树及相关操作(前,中,后,层序遍历)

news2024/11/17 3:45:02

欢迎来到 Claffic 的博客 💞💞💞

“春来无事,只为花忙。”

前言:

上一期给大家介绍了二叉树的一种顺序结构:堆,这一期承接上一期,给大家继续介绍二叉树的另一种结构:链式结构。


目录

🐽Part1:链式二叉树? 

1.前情提要 

2.创建一颗二叉树

🐷Part2:相关操作实现

1.遍历操作

1.1前序遍历

1.2中序遍历

1.3后序遍历

1.4层序遍历

2.其他操作

2.1二叉树结点个数

2.2二叉树高度

2.3第k层结点个数 

2.4判断是否为完全二叉树

2.5查找为x的结点

2.6二叉树销毁 


Part1:链式二叉树? 

1.前情提要 

这里的链式二叉树其实就是利用每个结点的左孩子和右孩子关系来创建的,方便快速手搓一个简单的二叉树。

2.创建一颗二叉树

其实方法很简单:

确定结点的结构 --> 根据左右孩子关系链接

//结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
//新结点的创建
BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->left = NULL;
	newnode->right = NULL;

	return newnode;
}

//链接
BTNode* CreatTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;

	return node1;
}

到这里,这颗二叉树的样子就有了:

Part2:相关操作实现

1.遍历操作

遍历可以清晰的明确二叉树的结构。

二叉树的遍历是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。 

按照规则,二叉树的遍历(按访问顺序)有: 

前序遍历:根节点-->左节点-->右结点;
中序遍历:左节点-->根节点-->右结点;

后序遍历:左节点-->右结点-->根节点;

层序遍历:简单说,就是二叉树由上到下,由左到右遍历。

1.1前序遍历

由于每次遍历都是 根节点-->左节点-->右结点,所以非常适合用递归来实现遍历。

前序遍历图解

面对二叉树遍历,既要看到大树,又能看到小树; 

可以看出,首先由顶部根节点进入,再递归左边,遇到空结点返回,再递归右结点... ...依次反复

那么就可以上代码了:

//前序遍历
void PreOder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->data);
	PreOder(root->left);
	PreOder(root->right);
}

为了更详细的理解,这里画一下代码的递归图解:

代码递归图解 

学会了前序遍历,剩余的中序遍历和后序遍历也就会了,它们之间只有访问结点的顺序不同。

1.2中序遍历

//中序遍历
void InOder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOder(root->left);
	printf("%d ", root->data);
	InOder(root->right);
}

1.3后序遍历

//后序遍历
void PostOder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOder(root->left);
	PostOder(root->right);
	printf("%d ", root->data);
}

1.4层序遍历

层序遍历与前三种遍历不同;

这里直接上演示图吧:

简单解释: 

双亲结点弹出,两个孩子节点就入 队列

是的,这里用到了队列 先入先出 的特点。

上代码: 

// 层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if (root)
		QueuePush(&q,root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->data);
		if (front->left)
			QueuePush(&q, front->left);

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

	QueueDestroy(&q);
}

2.其他操作

2.1二叉树结点个数

这里利用了分治思想,

即让每个根节点去统计孩子结点个数,再依次向上汇报;

还是利用递归:

// 二叉树节点个数  分治思想
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 :
				   BinaryTreeSize(root->left)
				   + BinaryTreeSize(root->right)
				   + 1; // +1是自己
}

2.2二叉树高度

二叉树的高度,是取左子树和右子树高度中最大者,

所以可以先利用递归分别保存左右子树的高度,再返回较大值:

//二叉树高度
int BinaryTreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int Heightleft = BinaryTreeHeight(root->left) + 1;
	int Heightright = BinaryTreeHeight(root->right) + 1;
	return Heightleft >= Heightright ? Heightleft : Heightright;
}

2.3第k层结点个数 

同样的,第k层结点个数包含左子树结点个数与右子树结点个数:

//第k层节点个数
int BinaryTreeKLevel(BTNode* root, int k)
{
	assert(k > 0);

	if (root == NULL)
		return 0;
	if (k == 1) // 顶部根节点的特殊情况
		return 1;
	return BinaryTreeKLevel(root->left, k - 1) 
		+ BinaryTreeKLevel(root->right, k - 1);
}

2.4判断是否为完全二叉树

还记得完全二叉树吗?

它的特点是 空结点连续 ,我们就可以利用这一个特点来判断;

判断一层连不连续,正好用到前面的层序遍历思想,利用 队列 来实现:

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

	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front == NULL)
		{
			break;
		}
		else
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
	}
	//判断
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front)
		{
			QueueDestroy(&q);
			return false;
		}
	}

	QueueDestroy(&q);
	return true;
}

2.5查找为x的结点

分左右结点来查找,若有多个满足条件的结点,返回先找到的结点指针:

//查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* lret = BinaryTreeFind(root->left, x);
	if (lret)
		return lret;
	BTNode* rret = BinaryTreeFind(root->right, x);
	if (rret)
		return rret;

	return NULL;
}

2.6二叉树销毁 

这个销毁也是要逐个销毁的,也要用到递归,分左子树销毁和右子树销毁:

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

代码已上传至 我的gitee

拿走不谢~ 


总结:

链式二叉树的实现~ 主要掌握四种遍历:前中后序遍历层序遍历,尽量搞懂是如何递归的,才会有更深刻的记忆~

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

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

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

相关文章

深度学习部署(十九): CUDA RunTime API YOLOV5后处理cpu解码以及gpu解码

跟着杜老师学AI 看看我们干了什么, 就是把bouding box恢复成框而已 1.1 知识点和先验知识 对于模型推理后的后处理,可以直接使用cuda核函数进行解码,效率比较高nms也可以在核函数里面实现这里演示了一个yolov5的实际案例,后续其他的操作都…

反序列化渗透与攻防(四)之Fastjson反序列化漏洞

Fastjson反序列化漏洞 Fastjson介绍 Fastjson是一个阿里巴巴开源的一款使用Java语言编写的高性能功能完善的JSON库,通常被用于将Java Bean和JSON 字符串之间进行转换。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,…

leedcode刷题(4)

各位朋友们,大家好。这两天我将为大家分享我在学习栈的过程中遇到的题目,我们一起来看看。 文章目录逆波兰表达式求值题目要求用例输入提示做题思路代码实现c语言实现代码Java语言实现代码有效的括号Java代码实现逆波兰表达式求值 leedcode之逆波兰表达…

Python工程师Java之路(t)使用Shell脚本部署SpringBoot

文章目录1、概述2、在服务器上安装Maven2、在服务器上安装Git3、Shell脚本4、SpringBoot部署测试1、概述 #mermaid-svg-MhYgFNGEE2jsSopb {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MhYgFNGEE2jsSopb .error-ic…

【中级软件设计师】—数据库系统考点总结篇(三)

【中级软件设计师】—数据库系统考点总结篇(三) 课程大纲与考点分布 1 数据库系统的体系结构 分布式数据库的透明性 1.1 三级模式—两级映射 1.2 数据库的设计过程 1.3 E-R模型 首先每个实体要单独转成一个关系模式,总共三个实体三个关系模式…

ubuntu20.04安装Intel核显QSV编译FFmpeg支持QSV硬件加速

Intel Video And Audio For Linux: libva: Libva is an implementation for VA-APIlibva下可以接入各种driver,以支持不同的设备 VA-API(Video Acceleration API): is an open-source library and API specification(规格说明,技术参数)libv…

现在的年轻人真会玩,开发界面都这么时尚,不服老都不行了

文章目录一、你还在用传统的开发界面吗二、年轻人的界面1.动漫型2.偶像型3.提神型三、更换背景的操作第一步第二步第三步一、你还在用传统的开发界面吗 不比不知道,一比吓一跳,都2023年了,你还在用Pycharm的默认背景写代码吗?已经…

深度学习训练营_第J5周_DenseNet+ SE-Net实战

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊|接辅导、项目定制 本周进行SE模块在DenseNet上的改进实验,之后将改进思路迁移到YOLOv5模型上测试 首先是学习SE模块 SE模块:Squeeze-an…

Nuxt - 超详细 Element 组件库主题颜色进行 “统一全局“ 替换,将默认的蓝色主题色更换为其他自定义颜色(保姆级教程,简易且标准全局替换主题色)

前言 如果需要纯 Vue 版本,请访问:这篇文章。 网上的文章可以用乱七八糟来形容了,各种奇葩的引入、安装各种东西,本文提供简洁且符合官方标准的解决方案。 Element UI 默认主题色是蓝色,很可能与我们设计稿不一致(比如设计稿是绿色主题), 这时候问题就出现了,难不成每…

Concept HDL学习资料汇总

本篇博文目录:一.concept HDL相关概念知识1. Concept HDL2.Concept HDL与Cadence的区别3.Concept HDL与Cadence CIS之间的转换问题二.Cadence软件安装1.Cadence 16.6安装2.Cadence 17.x安装三.concept HDL视频学习资料四.concept HDL博文学习资料五.concept HDL书籍/文档资料一…

【报错】Aanaconda环境下配置pytorch时报错 (Solved)

Aanaconda环境下配置pytorch时报错: 在命令行输入conda install pytorch torchvision torchaudio cpuonly -c pytorch安装pytorch时产生报错,报错信息如下: EnvironmentLocationNotFound: Not a conda environment: C:\Users\绀句細浜篭.conda\envs\py…

vite+vue3基础

vite创建项目指令 npm create vitelatest . 项目创建选择vue。 创建完成之后安装依赖 npm i || cnpm ivite项目下 引入文件需要配置路径 //如果文件路径 .///如果文件层 较深 配置 “/***”“../../”配置vite中的 路径(js版本支持node全局变量 ts版本不支持 types…

4款【新概念APP】对比+免费下载

4款【新概念APP】对比免费下载4款【新概念APP】对比免费下载新概念英语咖(体积小、无广告、全免费、不能倍速播放)新概念英语全册(免费,但强制广告,否则不能播放音频。可以倍速)新概念英语全四册&#xff0…

SpringBoot入门简介

SpringBoot简介 1.什么是SpringBoot SpringBoot基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用…

Android中的全量更新、增量更新以及热更新

在客户端开发过程中,我们可能会遇到这样一种需求:点击某个按钮弹出一个弹窗,提示我们可以更新到apk的某个版本,或者我们可以通过服务端接口进行强制更新。在这种需求中,我们是不需要通过应用商店来更新我们的apk的&…

【Hadoop/Java】基于HDFS的Java Web网络云盘

【Hadoop/Java】基于HDFS的Java Web网络云盘 本人BNUZ大学生萌新,水平不足,还请各位多多指教! 实验目的 熟悉HDFS Java API的使用;能使用HDFS Java API编写应用程序 实验要求 云盘系统通过互联网为企业和个人提供信息的储存、…

前后端部署+nginx配置

文章目录概要1、脚手架安装2、项目打包部署3、配置nginxEND概要 内容主要包括部署前端项目,nginx安装配置,以及后端项目的打包 1、脚手架安装 vue init webpack 项目运行(默认端口8080) npm run dev 如果前后端分离项目&…

使用Vue+el-form+form-validate实现管理端登录接口联调前准备工作实战

前言 这是《Vue + SpringBoot前后端分离项目实战》专栏的第7篇博客,感谢你能从成千上万篇博客中打开这一篇,和我一起学习前端开发实战知识,让我们一起开始吧。 目录 前言 一、上节回顾和本节介绍 1. 上节回顾

【可视化开发】echarts配置项——修改tooltip默认样式

修改tooltip默认样式 在可视化开发中我们通常会遇到修改tooltip样式问题,下面分享给大家代码片段和最终呈现效果 tooltip: {//鼠标悬浮框的提示文字trigger: "axis",axisPointer: {// 坐标轴指示器配置项。type: "none", // line 直线指示器 …

Vue3.0ElementPlus<input输入框自动获取焦点>

文章目录前言一、input-focus事件?二、使用步骤1.给input 设置ref 属性2.引入ref和nextTick3.在dialog打开事件中触发前言 记录一下自己最近开发vue3.0的小小问题~~ 最近在做项目时,dialog弹框事件需定位input焦点,方便用户可直接输入。原理…