【数据结构】二叉树详解(3)

news2024/11/23 1:02:10

⭐️ 前言

✨ 往期链接:【数据结构】二叉树详解(1)
在第一篇二叉树文章中,我们探讨了二叉树的链式结构定义与实现。二叉的遍历包含( 前序/中序/后序遍历 )及代码实现和递归流程图的详细讲解。还有一些二叉树的其他接口定义与实现,包含 BinaryTreeSize ( 计算二叉树结点的数量 )、BinaryTreeLeafSize( 计算二叉树叶子结点的数量 )、BinaryTreeKLevelSize( 计算二叉树第 k k k 层节点的个数 )、BinaryTreeFind( 二叉树中查找某个元素 )。
在这里插入图片描述


在这里插入图片描述


✨ 往期链接:【数据结构】二叉树详解(2)
在第二篇二叉树文章中,又是在第一篇的基础上又补充了一个接口的实现BinaryTreeDepth( 计算二叉树的深度 )
在这里插入图片描述


本期我们在前两篇的基础上,继续补充一些关于二叉树的其他接口实现。

⭐️ 二叉树的其他接口

// 二叉树的销毁
void BinaryTreeDestroy(BinaryTreeNode* root);
// 二叉树层序遍历(需要队列)
void LevelOrder(BinaryTreeNode* root);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BinaryTreeNode* root);

BinaryTreeDestroy 实现:

// 二叉树的销毁
// 后序遍历最优
void BinaryTreeDestroy(BinaryTreeNode* root) {
	if (root == NULL) {
		return;
	}

	BinaryTreeDestroy(root->left);
	BinaryTreeDestroy(root->right);

	free(root);
}

解析: 二叉树的销毁采用后序遍历是最优的,先销毁左子树在销毁右子树最后销毁根节点。


LevelOrder 实现:

// 二叉树层序遍历(需要队列)
void LevelOrder(BinaryTreeNode* root) {
	Queue q;
	QueueInit(&q);

	// 把根节点入队列
	if (root) {
		QueuePush(&q , root);
	}

	// 依次遍历队列
	while (!QueueIsEmpty(&q)) {
		// 取出队头节点
		QueueDataType front = QueueFront(&q);
		// 出队头节点
		QueuePop(&q);
		// 打印
		printf("%d " , front->value);
		// 左节点不为空 入队列
		if (front->left) {
			QueuePush(&q , front->left);
		}
		// 右节点不为空 入队列
		if (front->right) {
			QueuePush(&q , front->right);
		}
	}

	QueueDestroy(&q);
}

解析: 层序遍历需要依靠队列来实现,思路是把根节点入队列,循环判断队列不为空,若队列不为空则把当前队头节点取出并把队头节点的左右孩子依次入队,再删除队头数据。队列的代码以及实现:✨ 往期文章:【数据结构】栈和队列实现

在这里插入图片描述


BinaryTreeComplete 实现:

// 判断二叉树是否是完全二叉树
// 用到层序遍历的思想
bool BinaryTreeComplete(BinaryTreeNode* root) {
	Queue q;
	QueueInit(&q);
	// 根节点不为空入队列
	if (root) {
		QueuePush(&q , root);
	}
	// 检查队列
	while (!QueueIsEmpty(&q)) {
		// 取出队头数据
		QueueDataType front = QueueFront(&q);
		// 删除队头数据
		QueuePop(&q);
		// 如果当前对头节点存在则让当前节点左右节点入队
		if (front) {
			QueuePush(&q , front->left);
			QueuePush(&q, front->right);
		}
		else {
			break;
		}
	}
	// 继续检查队列
	// 如果全为空 则是完全二叉树
	// 如果有一个不为空 则不是完全二叉树
	while (!QueueIsEmpty(&q)) {
		QueueDataType front = QueueFront(&q);
		QueuePop(&q);
		if (front) {
			QueueDestroy(&q);
			return false;
		}
	}

	QueueDestroy(&q);
	return true;
}

解析: 判断当前二叉树是否是完全二叉树,使用到了层序遍历的思想。层序遍历是把根节点入队列,再依次检查队列是否为空,若不为空则取出队头数据,再判断子孩子是否存在,当把当前根节点出队列时,再将子孩子节点入队列,直至队列为空。完全二叉树满足 k − 1 k - 1 k1 层节点是满的,最后一层节点最少只有一个,最多也是满的(这种情况也叫做满二叉树)。当然完全二叉树最后一层节点之间还需要是连续的。
在这里插入图片描述


从上图可知:如果不是完全二叉树,当遇到第一个 NULL 时队列后面还有非空节点则就不是完全二叉树。因为完全二叉树的层序遍历是使存在的节点都在左侧 NULL节点都在右侧。所以我们在层序遍历的基础上把空节点也依次入队, 当碰到第一个 NULL 节点结束循环,再依次检查队列剩余的节点中是否有不为 NULL 的节点,若都为 NULL 则当前二叉树就是完全二叉树,若有非 NULL 节点,则当前就不是完全二叉树。

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

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

相关文章

基于netlify生成custom SSL certificate

(1)腾讯云申请 (2)域名控制台解析 (3)Nginx下载(crt: CA certificate Chain)

C++ 设计模式 ---- 接口隔离模式

“接口隔离”模式 在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题、甚至根本无法实现。采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案。典型模式:1、Facade2、Proxy3、…

MongoDB原生语句更新嵌套数组的值

一、更新一层嵌套数组 首先执行MongoDB原生语句脚本在user集合中产生一些样本数据,如下所示: db.user.insert({"_id":1,"title":"爱情公寓3","students":[{"student_id":1001,"student_name":"林宛瑜&quo…

Docker介绍及安装使用

Docker介绍及安装使用 一、Docker的概述1、Docker是什么?2、Docker的Logo3、Docker的设计宗旨(一次封装,到处运行)4、容器化越来越受欢迎的原因 二、Docker与虚拟机的区别三、Docker的使用场景四、Docker的核心概念1、镜像2、容器…

基于linux下的高并发服务器开发(第二章)- 2.25 sigprocmask 函数使用

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);- 功能:将自定义信号集中的数据设置到内核中(设置阻塞,解除阻塞,替换)- 参数:- how : 如何对内核阻塞信号集进行处理SIG_BLOCK: 将用户设…

【MySQl】MySQl中的乐观锁是怎么实现的

文章目录 前言一、乐观锁二、如何实现乐观锁呢,一般来说有以下2种方式2.1、使用数据版本(Version)记录机制实现2.2、乐观锁定的第二种实现方式和第一种差不多 前言 mysql中的乐观锁是怎么实现的?很多新手对此不是很清楚&#xff…

第一次参加【CSDN周赛(考试/编程竞赛)】第65期,应该注意些什么?都考什么题目?要具备什么知识?耗时__,我居然取得了__分的成绩

订阅专栏,学习更多干货知识!! 第一次参加 CSDN里的竞赛(考试),都需要注意些什么?考试都考了什么?要具备什么知识?本文带你了解一下!! 🤾🏿‍♂️目录 🌁一、先来看结果吧(有Bug?)🥕1.1 什么情况!🥕1.2 测评报告🥤1.2.1 选择题🥤1.2.2 编程题🥕1…

Redis持久化:分别启用rdb和aof,并查看是否有对应文件生成

一、rdb 简介:在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是Snapshot快照,它恢复时是将快照文件直接读到内存里。 1. 进入redis.conf文件中查看配置文件 [rootserver ~]# vim /usr/local/redis-stable/redis.conf 2.把持久化的…

《Docker数据管理:卷、挂载和持久化,保障容器环境数据安全》

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

【博客682】k8s apiserver bookmarks机制以更高效检测变更

k8s apiserver bookmarks机制以更高效检测变更 list-watch背景: List-Watch 是kubernetes中server和client通信的最核心的机制, 比如说api-server监听etcd, kubelet监听api-server, scheduler监听api-server等等,其实…

Paragon NTFS2023最新版Mac读写NTFS磁盘工具

Paragon NTFS for Mac是Mac平台上一款非常优秀的读写工具,可以在Mac OS X中完全读写、修改、访问NTFS硬盘、U盘等外接设备的文件。这款软件最大的亮点简书可以让我们读写 NTFS 分区,因为在Mac OS X 系统上,默认状态下我们只能读取NTFS 分区&a…

152. 乘积最大子数组

152. 乘积最大子数组 原题链接:完成情况:解题思路:参考代码: 原题链接: 152. 乘积最大子数组 https://leetcode.cn/problems/maximum-product-subarray/ 完成情况: 解题思路: 看好题目&…

Nginx 301重定向分析

参考; 404 - 墨天轮 深度硬核文:Nginx的301重定向处理过程分析 - 知乎 Nginx的301状态码处理逻辑设计 HTTP协议中3xx开头的状态响应码都是表示重定向的响应。根据RFC的定义: 301 Moved Permanently 302 Found 303 See Other 307 Temporary Redirect 301是永…

STL——String类(2)成员函数详解

目录 前言 一.String的成员函数: 1.基本成员函数 代码实验: 实验结果: 类对象每次扩容后的capacity数据展示: 1.2. resize():调整字符串大小 1.3reserve():请求更改该对象的容量capacity值 代码实验…

分组密码模式的填充

分组加密 在密码学中,分组加密(Block cipher),又称分块加密或块密码,是一种对称密钥算法。 它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。 常见的分组加密算法有: DES、3DES、AES、IDEA。 …

Ubuntu虚拟机部署配置

目录 虚拟机镜像下载 VirtualBox7下载 VirtualBox7安装镜像流程 创建虚拟机 虚拟机挂单独硬盘 网络设置 检查虚拟机配置 启动虚拟机 ubuntu配置 查询虚拟机IP地址 修改ROOT密码 更新apt NTP同步 挂载磁盘&关闭swap 虚拟机镜像下载 目前国内操作系统镜像源非常…

2023-07-19力扣今日二题

链接: 2737. 找到最近的标记节点 题意: 给一个n节点有向图,求节点s和点集marked中的最短距离,没有可以的到达的点则返回-1 解: 摇了一题困难过了2/3,搞不定了 没有负权边的单源最短距离,迪…

代码-【2 单链表A、B交集存放到C】

1)基本思想: A、B两个链表的元素均递增有序,所以可以按顺序,同时从A中和B中各取一个结点的值来对比;如果A中结点的值比较小,则A中的指针右移;如果B中的结点的值比较小,则B中的指针右…

优思学院|工程师学习六西格玛有什么用?

很久以前,世上没有当今盛行的各种简单易用的统计软件,那时复杂的统计分析只能依靠公司的统计顾问。而和他们在一起工作时,工程师必须知道怎样进行提问。 如果工程师缺乏对统计工具的认识,即使拿到正确的工具也于事无补。当顾问遇…

2. Makefile之目标、依赖(附示例)

一、本节概要 本专栏所有内容围绕Makefile官方文档进行刨析,给出详细具体示例做辅助理解手撕Makefile官方手册 二、Makefile中的目标和依赖 在一个简单的Makefile中,每条规则通常由以下几个部分组成: target ... : prerequisites ...rec…