数据结构二叉树链式存储

news2025/1/18 11:59:21

二叉树

  • 1. 二叉树的遍历
  • 1.1 前序遍历
  • 1.2 中序遍历
  • 1.3 后序遍历
  • 1.4 层序遍历
  • 2. 二叉树的高度
  • 3. 某一层结点的个数
  • 4. 计算二叉树的结点
  • 5. 叶子结点的个数
  • 6. 销毁二叉树

二叉树的顺序存储通过堆已经介绍过了,现在介绍二叉树的链式存储。关于二叉树,有 如下接口:遍历二叉树、计算二叉树的高度、某一层结点的个数、二叉树的结点数等。为了方便验证接口的正确性,这里创建了一个简单的二叉树。

定义二叉树结点的结构体

typedef char BTDataType;
typedef struct BTreeNode
{
	BTDataType val;
	struct BTreeNode* left;
	struct BTreeNode* right;
}BTNode;

创建树的代码如下,该代码只是为了验证接口而写的,并不是真正的创建树的方式,后续会介绍创建树的正确方式。

BTNode* buyNode(BTDataType x)
{
	BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
	if (newNode == NULL)
	{
		return NULL;
	}
	newNode->val = x;
	newNode->left = NULL;
	newNode->right = NULL;

	return newNode;
	
}

BTNode* createTree()
{
	BTNode* n1 = buyNode('A');
	BTNode* n2 = buyNode('B');
	BTNode* n3 = buyNode('C');
	BTNode* n4 = buyNode('D');
	BTNode* n5 = buyNode('E');
	BTNode* n6 = buyNode('F');

	n1->left = n2;
	n1->right = n3;
	n2->left = n4;
	n2->right = n5;
	n4->right = n6;

	return n1;
}

二叉树结构如下图
在这里插入图片描述

1. 二叉树的遍历

前序、中序和后序遍历是通过根节点的访问位置来分辨的。
前序:先访问根节点,然后访问左子树和右子树。
中序:先访问左子树,然后访问根节点,再访问右子树。
后序:先访问左子树和右子树,最后访问根节点。
以上三种遍历方式,左右子树也需要按照对应顺序
此外,介绍的这三种遍历方式都是通过递归实现的
层序:从二叉树的根节点开始,自上而下,从左到右逐层访问每一个结点。

1.1 前序遍历

上图二叉树的前序遍历为:ABDFEC

按照红色,绿色,蓝色的顺序看
在这里插入图片描述
代码如下

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

递归需要注意两点:1、分割的子问题 2、最小子问题(返回条件)
在遍历二叉树的例子中,子问题为对每一棵树都分为根和左右子树。最小子问题为该树为空树。

这里画递归图帮助大家理解
在这里插入图片描述
右子树类似,因此没有画全。按照函数调用顺序进行打印结果为:ABDFEC

1.2 中序遍历

上图遍历结果为:DFBEAC

和前序类似,只是换了根的访问顺序,就不赘述了。
代码如下

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

1.3 后序遍历

同理后序也是如此,直接上代码

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

对于上面三种遍历方式,测试代码和运行结果如图
在这里插入图片描述

1.4 层序遍历

层序遍历,需要用到先进先出的队列来辅助实现。

思路大致如下:入队根结点(根节点如果不为空),在进行出队操作,进行出队时,要先把队头结点的左右孩子结点入队。孩子结点为空时,不用入队。当队列为空时,二叉树的层序遍历结束。

过程如下图。
在这里插入图片描述
代码如下,用到的关于队列的接口在之前已经介绍过如何实现了,现在只需要将文件复制进项目即可。

添加过程如图
在这里插入图片描述
最后在项目中,将.c文件拖动到源文件目录下即可。

// 层序遍历
void TreeLevelOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
    //创建和初始化队列
	Queue TreeQ;
	QueueInit(&TreeQ);
	//插入根节点
	QueuePush(&TreeQ, root);
	while (!QueueEmpty(&TreeQ))
	{
		//获得队头
		BTNode* front= QueueFront(&TreeQ);

		//将队头结点的左右孩子结点入队
		if(front->left != NULL)
		QueuePush(&TreeQ, front->left);
		if (front->right != NULL)
		QueuePush(&TreeQ, front->right);
		//打印队头结点数值
		printf("%c ", front->val);
		//删除队头
		QueuePop(&TreeQ);
	}
}

测试运行结果如图
在这里插入图片描述

2. 二叉树的高度

计算树的高度,子问题为计算左右子树的高度,保留值较大的那一个。最小的子问题为计算空树高度,其高度为0。叶子结点高度为1。

代码如下

//树的高度
int TreeHeight(BTNode* root)
{
    //空树
	if (root == NULL)
	{
		return 0;
	}
	//叶子结点
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
    //递归左子树,计算左子树高度
	int left = TreeHeight(root->left);
	//递归右子树,计算右子树高度
	int right = TreeHeight(root->right);
    //返回较高的值,加1是因为需要包括本层高度
	return left > right ? left + 1 : right + 1;
}

力扣里也有此题,链接:计算二叉树的深度

题解代码如下

int calculateDepth(struct TreeNode* root) 
{
    if(root==NULL)
    {
        return 0;
    }
    if(root->left==NULL&&root->right==NULL)
    {
        return 1;
    }
    //这两句不能去掉,去掉后会导致调用函数计算出来的高度不会被保存起来
    //只会知道是左树高度大还是右树高度大,会导致频繁调用函数,最终运行超时
    int leftDepth=calculateDepth(root->left);
    int rightDepth=calculateDepth(root->right);

    return leftDepth>rightDepth?leftDepth+1:rightDepth+1;
}

把上面两句删除,在提交代码,删除前后的结果如下图。

删除前
在这里插入图片描述
删除后
在这里插入图片描述
当测试用例的二叉树足够大时,会使函数调用次数太多,最终运行超时。

3. 某一层结点的个数

计算任意一层结点的个数,层数小于等于高度。
在这里插入图片描述
代码如下

//第k层结点个数
int TreeKsize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return TreeKsize(root->left, k - 1) + TreeKsize(root->right, k - 1);
}

这里通过递归展开图帮助大家理解
在这里插入图片描述
假如A没有右子树,那么TreeKsize(root->right, k - 1) 会返回0,因为root->right==NULL。

4. 计算二叉树的结点

有了上面的理解,计算二叉树全部的结点可以转化为计算左右子树的结点数再加1(要包括自己)。最小子问题为空树,结点数为0

代码如下

//树的结点个数
int TreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	return TreeSize(root->left) 
		 + TreeSize(root->right) + 1;
}

5. 叶子结点的个数

同样可以转化为计算左右子树的叶子结点数。最小子问题为空树,返回0。当结点为叶子结点(左右子树都为NULL)时,返回1。

代码如下

// 叶子节点个数
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

6. 销毁二叉树

销毁二叉树时,不能从根节点开始销毁,销毁根节点后,会导致左右子树找不到。这里选择使用后序遍历的方式来销毁二叉树,先销毁左右子树再销毁根节点。

由于形参和实参都是一个指针,想要通过形参来修改实参的内容,需要传二级指针,因此代码是这样实现的。

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

对于上面接口的正确性进行验证,运行结果如下图

在这里插入图片描述
这里主要是用递归进行解决,递归的代码容易写,但是不太好理解,需要进行适当练习。

关于链式二叉树,就介绍到这里了,剩下的接口会通过OJ题来介绍。也会写一部分的OJ题,练练手。

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

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

相关文章

C#复习——变长参数和可选参数

变长参数——params 参数默认值 总结 配合泛型类实现迭代器的语法糖使用:

7.java openCV4.x 入门-Mat之转换、重塑与计算

专栏简介 💒个人主页 📰专栏目录 点击上方查看更多内容 📖心灵鸡汤📖我们唯一拥有的就是今天,唯一能把握的也是今天建议把本文当作笔记来看,据说专栏目录里面有相应视频🤫 🧭文…

电商API接口|Python爬虫 | 如何用Python爬虫一天内收集数百万条电商数据?

你是否遇到过需要收集大量数据的问题?比如需要分析市场趋势,或者是想要了解某个领域的发展动态。手动收集这些数据既费时又费力,而且很难保证数据的准确性和完整性。那么有没有一种方法可以快速高效地收集大量数据呢? 技术汇总 …

xss.pwnfunction-Ma Spaghet!

根据代码得知 这个是根据get传参的并且是由someboby来接收参数的 所以 <script>alert(1137)</script> js并没有执行因为 HTML5中指定不执行由innerHTML插入的<script>标签 所以 ?somebody<img%20src1%20onerror"alert(1337)"> 这样就成…

双指针-移动零

首先不能复制&#xff0c;只能在原数组是哪个操作&#xff0c;那么很多集合的方式就不行了。当然在现实开发中肯定是可以的。目前按照题目来说是不可以的。所以我们可以思考下&#xff0c;是否可以通过交换来实现。 初始化一个变量 to 为 0。这个变量的目的是跟踪非零元素应该…

【MySQL】增删改查操作(基础)

文章目录 1、新增操作&#xff08;Create&#xff09;1.1单行数据全列插入1.2多行数据指定列插入 2、查询操作&#xff08;Retrieve&#xff09;2.1全列查询2.2指定列查询2.3指定列查询2.4别名&#xff08;as&#xff09;2.5去重&#xff08;distinct&#xff09;2.6排序&#…

java数据结构与算法刷题-----LeetCode405. 数字转换为十六进制数

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 分组位运算 分组位运算 这道题正常来说可以用转换7进制的思想来&…

Linux第5课 Linux目录介绍

文章目录 Linux第5课 Linux目录介绍一、打开系统目录二、查看系统目录 Linux第5课 Linux目录介绍 系统目录就是指操作系统的主要文件存放的目录&#xff0c;目录中的文件直接影响到系统是否正常工作&#xff0c;了解这些目录的功能&#xff0c;对使用系统会有很大的帮助。 一…

ChatGPT(3.5版本)开放无需注册:算力背后的数据之战悄然打响

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

JAVA8 新特性StreamAPI使用(二)

一、使用StreamAPI&#xff0c;&#xff08;基于数据模型——客户、订单和商品&#xff0c;实体关系图如下&#xff0c;客户可以有多个订单&#xff0c;是一对多的关系&#xff0c;而产品和订单的关系是多对多的&#xff09;需求如下&#xff1a; 二、Stream API思维导图 三、需…

2024.4.1-[作业记录]-day06-认识 CSS(三大特性、引入方式)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; day06-认识 CSS(三大特性、引入方式) 文章目录 day06-认识 CSS(三大特性、引入方式)作业…

上位机图像处理和嵌入式模块部署(qmacvisual之tcp服务器端)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 上面一篇&#xff0c;我们谈到了tcp客户端&#xff0c;另外一种连接方法就是tcp服务器端。事实上&#xff0c;对于第三方系统&#xff0c;大多数情…

蓝桥杯杯赛之深度优先搜索优化《1.分成互质组》 《 2.小猫爬山》【dfs】【深度搜索剪枝优化】【搜索顺序】

文章目录 思想例题1. 分成互质组题目链接题目描述【解法一】【解法二】 2. 小猫爬山题目链接题目描述输入样例&#xff1a;输出样例&#xff1a;【思路】【WA代码】【AC代码】 思想 本质为两种搜索顺序&#xff1a; 枚举当前元素可以放入哪一组枚举每一组可以放入哪些元素 操…

医院设置

广度优先和深度优先做这个题 题目描述 设有一棵二叉树&#xff0c;如图&#xff1a; 其中&#xff0c;圈中的数字表示结点中居民的人口。圈边上数字表示结点编号&#xff0c;现在要求在某个结点上建立一个医院&#xff0c;使所有居民所走的路程之和为最小&#xff0c;同时约定…

记第一次eudsrc拿到RCE(上)

目录 前言 个人介绍 挖洞公式 漏洞介绍 CLI命令注入介绍 RCE漏洞介绍 漏洞详情 漏洞点1 漏洞点2 修复建议 总结 前言 免责声明 以下漏洞均已经上报漏洞平台。请勿利用文章内的相关技术从事非法测试。若因此产生一切后果与本博客及本人无关。 本来想大学四年都不会…

【单片机】74HC4052电路图,单片机端口复用电路

74HC4052电路图 如下图&#xff0c;还是很好理解&#xff0c;PA9、PA10是单片机引脚。 当A和B是00&#xff0c;那么就是X-COM和0X短路&#xff0c;Y-COM和0Y短路。 当A和B是01&#xff0c;那么就是X-COM和1X短路&#xff0c;Y-COM和1Y短路。 以此类推。 74HC 工艺可以直接3.…

51单片机入门_江协科技_21~22_OB记录的笔记

21. LED点阵屏 21.1. LED点阵屏介绍 •LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合&#xff0c;如汽车报站器、广告屏以及公告牌等 •LED点阵屏分类 按颜色&#xff1a;单…

通过Omnet++官网tictoc教程学习在Omnet++中构建和运行仿真 Part1Part2

introduce开始模型介绍构建项目添加 NED 文件添加C 文件添加 omnetpp.ini总结 运行仿真启动仿真程序运行仿真调试运行时错误崩溃断点调试下一事件 调试/运行 日志序列图可视化 Omnet官网 TicToc教学 introduce 在 Omnet安装完成后&#xff0c;samples/tictoc 中有该例子的完整…

windows部署Jenkins并远程部署tomcat

目录 1、Jenkins官网下载Jenkins 2、安装Jenkins 3、修改Home directory 4、插件安装及系统配置 5、Tomcat安装及配置 5.1、修改配置文件,屏蔽以下代码 5.2、新增登录用户 5.3、编码格式修改 5.4、启动tomcat 6、Jenkins远程部署war包 6.1、General配置 6.2、Sourc…

基于卷积神经网络的大米品种分类系统(pytorch框架)【python源码+UI界面+前端界面+功能源码详解】

功能演示&#xff1a; 大米品种分类系统&#xff0c;基于vgg16&#xff0c;resnet50卷积神经网络&#xff08;pytorch框架&#xff09;_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积神经网络的大米品种分类系统是在pytorch框架下实现的&#xff0c;系统中有两…