椋鸟数据结构笔记#8:二叉树的遍历、创建与销毁

萌新的学习笔记,写错了恳请斧正。

链式二叉树

这篇笔记我们讨论基于链式二叉树,其节点的数据结构如下:

typedef int BTDatatype;

typedef struct BTNode
{
    BTDataType data;
    struct BTNode* left;
    struct BTNode* right;
} BTNode;
二叉树的遍历

先了解关于二叉树的遍历再去了解二叉树的创建会更轻松一点。

二叉树的遍历基本分两类,一类是深度优先的,另一类是广度优先的。

对于深度优先的遍历,又分为前序遍历、中序遍历、后序遍历;对于广度优先的遍历,只有层序遍历。

前序遍历(PreOrder Traversal)

从根节点开始,对于每一个子树,先访问其根节点,再访问其左子树和右子树。

比方说,对于下面这个二叉树:

在这里插入图片描述

我们先访问其根节点1,然后是其左子树
对于其左子树,我们还是先访问其根节点2,然后是其左子树
我们继续访问该节点的左子树3,然后是3的左子树
发现3的左子树为空,那么返回访问3的右子树
3的右子树也为空,这是2的左子树访问完了就轮到2的右子树了
2的右子树为空,那么1的左子树就访问完了轮到1的右子树
1的右子树为4,访问完根节点4后访问其左子树5
5的左子树右子树为空,那么4的左子树就访问完了
最后是4的右子树6

所以最终节点的访问顺序为:

1–>2–>3–>N–>N–>N–>4–>5–>N–>N–>6–>N–>N

下面这张图可能更直观些:

在这里插入图片描述

下面给出其实现(递归的思想):

void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%c ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}
中序遍历(InOrder Traversal)

中序遍历对每一个子树则是先访问其左子树,随后是根节点和右子树。

对于上方的示例,如果用中序遍历,顺序就会变为:

N–>3–>N–>2–>N–>1–>N–>5–>N–>4–>N–>6–>N

下面给出其实现:

void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%c ", root->data);
	BinaryTreeInOrder(root->right);
}
后序遍历(PostOrder Traversal)

同理,后序遍历就是最后访问根节点,对于上例的顺序为:

N–>N–>3–>N–>2–>N–>N–>5–>N–>N–>6–>4–>1

下面给出其实现:

void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeInOrder(root->left);
	BinaryTreeInOrder(root->right);
	printf("%c ", root->data);
}
层序遍历(LevelOrder Traversal)

层序遍历就是逐层的一个一个元素遍历,与前几个一条路走到底再拐回来的遍历方式不同

想要实现二叉树的层序遍历,就不仅仅是递归这么简单了,我们需要借助之前学的数据结构:队列

层序遍历的步骤:

  1. 初始化队列: 首先,将根节点放入队列中。
  2. 遍历队列: 当队列不为空时,重复以下步骤:
    • 从队列中取出一个元素(节点)。
    • 访问这个节点。
    • 如果这个节点有左子节点,则将左子节点放入队列。
    • 如果这个节点有右子节点,则将右子节点放入队列。

通过这种方式,可以保证每个节点都按照层序被访问一次,同时每个节点只会被放入队列一次,从而实现二叉树的层序遍历。

对于这个方法的理解,ChatGPT给出了一个比较生动的例子:

想象一下,你在组织一场大型的派对游戏,游戏的目标是确保每个人都能按顺序获得一个气球。派对的参与者按照到达的顺序站成一列,每个人都可能带着一两个朋友。在这个比喻中,每个参与者就像是树中的一个节点,他们带来的朋友分别对应于这个节点的左右子节点。

  1. 开始游戏: 游戏开始时,你手里只有一个气球,而第一个参与者(对应于树的根节点)站在你面前。你将这个气球给了他,并询问是否有朋友一起来。他回答说带了两个朋友(左右子节点)。
  2. 组织队列: 为了管理游戏的顺序,你拿出一个大篮子(对应于队列),让第一个参与者的朋友们按照他们被介绍的顺序站到篮子后面。现在,篮子里有两个人在等待气球。
  3. 进行派对游戏: 接下来,你从篮子(队列)的前端取出一个人(节点),给他一个气球,并询问他是否也有带朋友来。如果有,他的朋友们也按顺序加入到篮子的末尾。
  4. 重复步骤: 按照这个流程,你一直重复,总是从篮子的前端取人,给他气球,然后将他的朋友们(如果有的话)加入到篮子的末尾。

通过这个过程,每个参与者都会按照他们到达派对的顺序获得气球。同样地,在二叉树的层序遍历中,我们利用队列这一数据结构,确保了每个节点都能按照它们在树中的层级顺序被访问。就像在游戏中一样,通过不断地将朋友(子节点)加入队列并按顺序访问,我们能够遍历树中的每一个节点,从而实现层序遍历。

下面给出其实现:

void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root != NULL)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front->_left != NULL)
		{
			printf("%c ", front->_data);
			QueuePush(&q, front->_left);
			QueuePush(&q, front->_right);
		}
		else
		{
			printf("NULL ");
		}
	}
	printf("\n");

	QueueDestory(&q);
}
二叉树的创建与销毁

我们以一道题为例:

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

有了前面的内容这里就很好完成了,实现如下:

BTNode* BuyBTNode(BTDataType x)
{
	BTNode* new = (BTNode*)malloc(sizeof(BTNode));
	if (new == NULL)
	{
		perror("malloc");
		exit(EXIT_FAILURE);
	}
	new->_data = x;
	new->_left = NULL;
	new->_right = NULL;
	return new;
}

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (*pi >= n || a[*pi] == '#') 
	{
		(*pi)++; // 跳过当前的'#'或越界的元素
		return NULL;
	}
	BTNode* root = BuyBTNode(a[(*pi)++]);
	root->_left = BinaryTreeCreate(a, n, pi);
	root->_right = BinaryTreeCreate(a, n, pi);
	return root;
}

而二叉树的销毁就更加简单了:

void BinaryTreeDestroy(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestroy(&(*root)->_left);
	BinaryTreeDestroy(&(*root)->_right);
	free(*root);
	*root = NULL;
}
其他二叉树相关
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right);
}
// 二叉树叶子节点个数
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层节点个数
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的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	BTNode* ret = BinaryTreeFind(root->_left, x);
	if (ret != NULL)
	{
		return ret;
	}
	return BinaryTreeFind(root->_right, x);
}
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
		Queue q;
	QueueInit(&q);
	if (root != NULL)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
		{
			break;
		}
		QueuePush(&q, front->_left);
		QueuePush(&q, front->_right);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return 0;
		}
	}
	QueueDestroy(&q);
	return 1;
}

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

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

相关文章

STM32CubeMX配置步骤详解六 —— 时钟及其它内部参数配置(1)

接前一篇文章:STM32CubeMX配置步骤详解五 —— 基础配置(2) 本文内容主要参考: STM32CUBEMX配置教程(一)基础配置-CSDN博客 野火STM32系列HAL库开发教程 —— 第12讲 STM32的复位和时钟控制(第…

环形链表 - LeetCode 热题 25

大家好!我是曾续缘🥰 今天是《LeetCode 热题 100》系列 发车第 25 天 链表第 4 题 ❤️点赞 👍 收藏 ⭐再看,养成习惯 环形链表 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可…

2-3 AUTOSAR ASW Runable可运行实体

返回总目录->返回总目录<- 目录 一、概述 二、RTE Event 一、概述 运行实体(Runnable Entity,RE)是一段可执行的代码,其包含实际实现的函数(具体的逻辑算法或者操作)。一个软件组件可以包含一个或者多个运行实体。 Runnable就是SWC中的函数,而在AutoSAR架构在被…

【云计算】云数据中心网络(一):VPC

云数据中心网络&#xff08;一&#xff09;&#xff1a;VPC 1.什么是 VPC2.VPC 的组成2.1 虚拟交换机2.2 虚拟路由器 3.VPC 网络规划3.1 VPC 数量规划3.2 交换机数量规划3.3 地址空间规划3.4 不同规模企业地址空间规划实践 4.VPC 网络高可靠设计4.1 单地域单可用区部署4.2 单地…

[StartingPoint][Tier1]Funnel

Task 1 How many TCP ports are open? (打开了多少个 TCP 端口&#xff1f;) # nmap -sS -T4 10.129.224.226 --min-rate 1000 2 Task 2 What is the name of the directory that is available on the FTP server? (FTP 服务器上可用的目录名称是什么&#xff1f;) $ n…

爬虫 新闻网站 以湖南法治报为例(含详细注释,控制台版) V3.0 升级 自定义查询关键词、时间段、粗略判断新闻是否和优化营商环境相关,避免自己再一个个判断

目标网站&#xff1a;湖南法治报 爬取目的&#xff1a;为了获取某一地区更全面的在湖南法治报的已发布的和优化营商环境相关的宣传新闻稿&#xff0c;同时也让自己的工作更便捷 环境&#xff1a;Pycharm2021&#xff0c;Python3.10&#xff0c; 安装的包&#xff1a;requests&a…

强力推荐一款具有故障保护和CAN FD 功能的隔离CAN收发器 SiLM5150S

控制器局域网总线(CAN&#xff0c;Controller Area Network)&#xff0c;是一种用于实时应用的串行通讯协议总线&#xff0c;它可以使用双绞线来传输信号&#xff0c;是目前应用最广泛的现场总线之一。CAN协议具有实时性强、可靠性高、传输距离远的特点&#xff0c;适用于各种复…

Python中定时任务调度利器APScheduler

在Python开发中&#xff0c;经常需要执行一些定时任务&#xff0c;比如定期发送邮件、定期更新数据等。APScheduler&#xff08;Advanced Python Scheduler&#xff09;是一个强大且易用的Python库&#xff0c;专门用于定时任务调度。它提供了丰富的调度接口&#xff0c;使得定…

51单片机学习笔记14 LCD1602显示屏使用

51单片机学习笔记14 LCD1602显示屏使用 一、LCD1602介绍1. 简介2. 引脚定义3. DDRAM4. 字模5. 指令&#xff08;1&#xff09;清屏指令 0x01&#xff08;2&#xff09;光标归位指令 0x02&#xff08;3&#xff09;进入模式设置指令 0x06&#xff08;4&#xff09;显示开关控制指…

短毛猫也能吃得好!揭秘宠物店推荐猫粮的秘密!

短毛猫通常毛发短而浓密&#xff0c;性格温顺&#xff0c;容易打理。那么&#xff0c;对于我们这些爱护短毛猫的朋友们来说&#xff0c;选择一款合适的猫粮就显得尤为重要了。今天&#xff0c;我要向大家推荐一款我个人非常喜欢的猫粮——福派斯三文鱼益生菌猫粮。 &#x1f41…

SAP操作教程第7期:SAP B1日期偏离允许范围解决方法

作为一种灵活的工具&#xff0c;自定义能够充分满足企业多样的需求。它允许你根据个人或团队的具体需求和情况来调整计划。通过自定义&#xff0c;你可以根据优先级、时间表、资源分配和风险管理等因素&#xff0c;制定更具体、实用的计划。 下面我们将详细探讨在SAP Business …

ARM_04

1.总结二进制信号量和计数型信号量的区别&#xff0c;以及他们的使用场景。 二进制信号量&#xff1a;只有0和1&#xff0c;一般用于资源共享时使用 计数型信号量&#xff1a;值一般是大于等于2的&#xff0c;可以实现同步互斥作用 2.使用技术型信号量完成生产者和消费者模型…

vue快速入门(九)事件绑定参数传递

注释很详细&#xff0c;直接上代码 上一篇 新增内容 事件绑定基础模板事件传参方法 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, init…

蓝桥杯嵌入式(G431)备赛笔记——LED

目录 cubeMX配置&#xff1a; 代码模板&#xff1a; 注意&#xff1a; cubeMX配置&#xff1a; 原理图&#xff0c;其中PD2高电平使能锁存器&#xff0c;PC8-15默认给高电平&#xff0c;放置上电初始化LED亮 74HC573是八路输出锁存器 1脚是使能&#xff0c;低电平有效&#…

【JavaEE】浅谈线程(一)

线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子&#xff08;线程便利性的体现&#xff09; 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1&#xff09;通过继承Thread 重写run2&#xff09;使用Runnable接口 重写ru…

Ubuntu系统同时使用AMD和NVIDIA GPU出现的问题及解决

问题产生&#xff1a; Ubuntu 22.04系统同时使用了AMD W7900和NVIDIA GTX 1070Ti&#xff0c;想用1070Ti做显示&#xff0c;W7900做运算。结果Ubuntu 22.04系统不能启动了。 解决方法&#xff1a; 同时按下Ctrl和Alt键&#xff0c;并保持按住。在此过程中&#xff0c;按一下…

Windows Server 2012 R2安装远程桌面服务

文章目录 一、打开【服务器管理器】二、点击【添加角色和功能】三、点击【下一步】四、点击【下一步】五、点击【下一步】![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/05b61a830faf477e81f858ec00bbdfff.png)六、勾选【远程桌面服务】→点击【下一步】七、点击【…

ruoyi-nbcio-plus基于vue3的flowable流程设计器组件的升级修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

删除有序链表中的重复元素

. - 力扣&#xff08;LeetCode&#xff09; 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,5]示例 2&…

软考系统规划与管理师-第1章考点思维导图

系规&#xff5c;教程第1章脑图发布&#xff0c;用4幅图掌控信息系统综合知识的考点地图 2024年指尖疯在9年之后&#xff0c;首次扩展到系规课程。 虽然目前系统规划与管理师的教程是否改版存在不确定性&#xff0c;但是不影响咱们先概要了解当前的教程&#xff0c;使用思维导图…