【数据结构】二叉树链式结构的实现(三)

news2024/12/23 12:33:46

目录

一,二叉树的链式结构

二,二叉链的接口实现

        1,二叉链的创建

        2,接口函数

        3,动态创立新结点

        4,创建二叉树

        5,前序遍历

        6,中序遍历

        7,后序遍历

三,结点个数以及高度等

        1,接口函数

        2,结点个数

        3,叶子结点个数

        4,二叉树高度

        5,二叉树第k层结点个数

        6,二叉树查找值为x的结点


一,二叉树的链式结构

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系;

通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。

链式结构又分为二叉链和三叉链,这里我们学习二叉链;

 二叉树是:

1,空树

2,非空:根节点,根节点的左子树、根节点的右子树组成的。

从图示中可以看出,二叉树定义是递归式的也称递归树,因此后序基本操作中基本都是按照该概念实现的;

 二叉链结构图示;

 

二,二叉链的接口实现

        1,二叉链的创建

typedef int BTDataType;
//二叉链
typedef struct BinaryTreeNode
{
	BTDataType data; // 当前结点值域	
	struct BinaryTreeNode* left; // 指向当前结点左孩子
	struct BinaryTreeNode* right; // 指向当前结点右孩子
}BTNode;

首先创建一个结构体表示二叉链data是当前结点的值域,BTDataType是储存的值的数据类型;

left是指向当前结点左孩子right是指向当前结点右孩子

这里的BTDataTypeint的重命名,也可以说是数据类型的重命名,这样统一化方便后续更改;

        2,接口函数

//动态创立新结点
BTNode* BuyNode(BTDataType x);
//创建二叉树
BTNode* GreatBTree();
//前序遍历
void PrevOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后序遍历
void PostOrder(BTNode* root);

这是以上要实现的接口函数;

        3,动态创立新结点

//动态创立新结点
BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	assert(newnode);
	newnode->data = x;
	newnode->left = NULL;
	newnode->right = NULL;
	return newnode;
}

后面创立新结点时直接调用此函数,一定要向堆区申请空间,这样函数结束空间会保留不会被回收;

data赋新值,leftright都指向空,再返回结点指针即可;

        4,创建二叉树

//创建二叉树
BTNode* GreatBTree()
{
	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;
}

然后我们申请结点来构造二叉树,通过链接将新结点链接起来;

创建的二叉树结构图示如下:

        5,前序遍历

//前序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

二叉树的前序,中序,后续遍历都是同一种思路:

1. 前序遍历(Preorder Traversal 亦称先序遍历)——根结点---->左子树--->右子树

2. 中序遍历(Inorder Traversal)——左子树--->根结点--->右子树

3. 后序遍历(Postorder Traversal)——左子树--->右子树--->根结点

这里要用到递归思想:这里NULLN表示,建议画图来理解,一层一层遍历下去;

前序遍历:

先访问根结点(1)然后访问其左子树(2)打印 1

此时根结点为(2)然后访问其左子树(3)打印1 2

此时根结点为(3)然后访问其左子树(NULL)打印1 2 3

此时根结点为(NULL)return NULL到(3),然后访问(3)的右子树(NULL)打印1 2 3 N

此时根结点为(NULL)return NULL到(3),此时对(3)也就是对(2)的左子树的访问结束了,然后访问(2)的右子树(NULL);打印1 2 3 N N

此时根结点为(NULL)return NULL到(2),此时对(2)也就是对(1)的左子树访问结束了,然后访问(1)的右子树(4)打印1 2 3 N N N

此时根结点为(4)然后访问其左子树(5)打印1 2 3 N N N 4

此时根结点为(5)然后访问其左子树(NULL)打印1 2 3 N N N 4 5

此时根结点为(NULL)return NULL到(5)然后访问(5)的右子树(NULL)打印1 2 3 N N N 4 5 N

此时根结点为(NULL)return NULL到(5)此时对(5)也就是对(4)的左子树的访问结束了,然后访问(4)的右子树(6)打印 1 2 3 N N N 4 5 N N

此时根结点为(6)然后访问其左子树(NULL)打印1 2 3 N N N 4 5 N N 6

此时根结点为(NULL)return NULL到(6)然后访问(6)的右子树(NULL)打印1 2 3 N N N 4 5 N N 6 N

此时根结点为(NULL)return NULL到(6),此时对(6)也就是对(4)的右子树的访问结束了,此时对(4)也就是对(1)的右子树的访问结束了,此时对(1)的访问也结束了,前序遍历也就结束了;打印1 2 3 N N N 4 5 N N 6 N N

图解思路示例:

    

BTNode* root = GreatBTree();
//前序遍历
PrevOrder(root);

这就是前序遍历;

        6,中序遍历

//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	PrevOrder(root->left);
	printf("%d ", root->data);
	PrevOrder(root->right);
}

中序遍历:左子树--->根结点--->右子树

跟前序遍历思路一致,就是换了一下访问的顺序,按照前序遍历的思路来就完事了;

//中序遍历
InOrder(root);
printf("\n");

        7,后序遍历

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	PrevOrder(root->left);
	PrevOrder(root->right);
	printf("%d ", root->data);
}

后序遍历:左子树--->右子树--->根结点

思路还是一致的,就是换了一下访问顺序,前,中,后序遍历的思路都是一致的,只要搞清楚其中一个就全部拿捏了;

//后续遍历
PostOrder(root);
printf("\n");

 这里对二叉链的基础遍历就实现完全了,有人说还有一个层序遍历,这个遍历需要用到队列,目前C语言阶段实现太过于繁琐,后序博主会补上;

三,结点个数以及高度等

像此类问题也都是递归问题,更加看重我们对函数栈帧的理解;

        1,接口函数

//结点个数
int	SumNode(BTNode* root);
//叶子结点个数
int LeafNode(BTNode* root);
//二叉树高度
int HeightTree(BTNode* root);
//二叉树第k层结点个数
int BTreeLeveSize(BTNode* root, int k);
//二叉树查找值为x的结点
BTNode* BTreeFine(BTNode* root, int x);

以上是要实现的函数;

        2,结点个数

//结点个数
int SumNode(BTNode* root)
{
	return root == NULL ? 0 : SumNode(root->left) + SumNode(root->right) + 1;
}

递归其实说难也难,说不难也不难,是有技巧在里面的;

1,大事化小:根结点为(1)的二叉树的结点总和==>左子树(2)的结点总和加上右子树(4)的结点总和再加上本身的结点个数1,然后根结点为(2)的结点总和==>左子树(3)的总和加上NULL1,这就是规律;【(1)=(2)+(4)+1 】

2,结束条件,当结点为NULL时返回0

//结点个数
printf("%d\n", SumNode(root));

        3,叶子结点个数

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

 

大事化小:求根结点为(1)的二叉树的叶子节点的个数==>其左子树(2)加上其右子树(4)的叶子节点的个数;【(1)=(2)+(4)

结束条件:当结点为NULL时返回0,当结点的左右子树都为NULL时返回1;

        4,二叉树高度

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

大事化小:求根结点为(1)的二叉树的高度==>其左子树(2)与右子树(4)中高的一颗的高度加上本身的高度1;【(1)=(2)>(4)?(2)+1:(4)+1 】

结束条件:当结点为NULL时返回0;

//二叉树高度
printf("%d\n", HeightTree(root));

        5,二叉树第k层结点个数

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

大事化小:求根结点为(1)的二叉树第K层的结点个数==>其左子树(2)加上右子树(4)中第K-1层结点的个数;【(1)=(2)+(4)

结束条件:当结点为NULL时返回0,K等于1时返回1;

//二叉树第k层结点个数
printf("%d\n", BTreeLeveSize(root,3));

        6,二叉树查找值为x的结点

//二叉树查找值为x的结点
BTNode* BTreeFine(BTNode* root, int x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	if (BTreeFine(root->left, x) == NULL)
	{
		return BTreeFine(root->right, x);
	}
	else
	{
		return BTreeFine(root->left, x);
	}
}

大事化小:查找根结点为(1)的二叉树中值为x的结点==>查找其左子树(2)与右子树(4)中值为x的结点;

结束条件:当结点为NULL时返回NULL当结点的值为x时返回该结点;

思路:所以当其中一个子树不为NULL时就是所求的结点,如果左子树不为空则返回左子树的结点,否则返回右子树的结点,如果左右都为空那也返回右子树的结点;

//二叉树查找值为x的结点
BTNode* ret = BTreeFine(root, 6);
printf("%d\n", ret->data);

ret = BTreeFine(root, 3);
printf("%d\n", ret->data);

到这里就结束了,通过这些题目也充分的认识了二叉树(递归树),这就是递归算法,还是要多画图来理解,递归基层的知识就是函数栈帧的创建与销毁

第三阶段就到这里了,这阶段带大家了解一下二叉树(递归树)的递归思想;

后面博主会陆续更新;

如有不足之处欢迎来补充交流!

完结。。


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

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

相关文章

嵌入式学习笔记(25)串口通信的基本原理

三根通信线:Tx Rx GND (1)任何通信都要有信息作为传输载体,或者有线的或则无线的。 (2)串口通信时有线通信,是通过串口线来通信的。 (3)串口通信最少需要2根&#xff…

“熊猫杯” | 赛宁网安获网络安全优秀创新成果大赛优胜奖

9月11日,四川省2023年国家网络安全宣传周正式启动。由四川省委网信办指导,中国网络安全产业联盟(CCIA)主办,成都信息工程大学、四川省网络空间安全协会承办的“2023年网络安全优秀创新成果大赛—成都分站赛(暨四川省‘…

Linux HTTP协议

目录 1.浏览器与服务器通信过程2.HTTP请求报头(1)HTTP的请求报头结构(2)HTTP的请求方法 3.HTTP应答报头(1)HTTP的应答报头结构(2) HTTP的应答状态 1.浏览器与服务器通信过程 浏览器…

小程序源码:多功能口袋工具箱微信小程序源码-带流量主|云开发(更新)

这里主要分享多功能口袋工具箱微信小程序源码,有带流量主,而且超多功能工具箱组合的微信小程序源码。无需服务器即可搭建,可以设置流量主赚取收益。 源码链接: 网盘源码 密码:hma8 工具箱的应用一览: 1…

部署kibana可视化平台

部署kibana可视化平台 案例版本:kibana 8.6.2 1、下载 去官网中查找与安装的ES版本一致的安装包:官网kibana下载。 可以选择自行下载好后放入服务器中进行安装,也可以使用wget下载: # 下载 cd /home/elasticsearch/kibana wge…

LeetCode 1132.申请的报告2

数据准备 Create table If Not Exists Actions (user_id int, post_id int, action_date date, action ENUM(view, like, reaction, comment, report, share), extra varchar(10)); create table if not exists Removals (post_id int, remove_date date); Truncate table Act…

【ccf-csp题解】第2次csp认证-第四题-最优配餐-多源BFS

题目描述 思路讲解 这道题的数据量是10^6,直接用floyd算法,肯定是不行的 此处介绍新的思路:多源BFS 我们的核心目的是,对于每一个终点(即此处的顾客)能够找到离它最近的源点(即此处的餐馆&am…

GFS分布式存储

一,gfs简介 GlusterFS 是一个开源的分布式文件系统,由存储服务器、客户端以及NFS/Samba 存储网关(可选,根据需要选择使用)组成。没有元数据服务器组件,这有助于提升整个系统的性能、可靠性和稳定性。 传统的…

第七章 系统管理和维护

第七章 系统管理和维护 ​ 当我们要登录系统或访问系统的某个资源时,通常都要求输入用户名和密码,从系统的角度看,用户就是一种进行认证或授权的标识。只有通过认证的用户才能访问相应的资源,而对于同一个资源,不同的…

再获新突破!移远通信RedCap模组拿下首张端网协同测评证书

为进一步推动5G技术的商用和普及,今年8月初,移远通信与广东联通联合建立了5G端网能力研究联合实验室(以下简称“联合实验室”),双方将在5G及RedCap各项性能的研究方面展开深入合作。广东联通网络产品创新中心总经理潘桂…

恒运资本:股市几点开盘和收盘?

股票商场在股票生意日打开,每个国家的股票商场都有自己的开盘和收盘时间。在本文中,我们将分析股市开盘和收盘时间的重要性,以及股市如安在纷歧起区的运作。我们还将讨论股市开盘和收盘时间的改动,以及这些改动对股票商场的影响。…

JVM核心参数图解-整理

一、VM核心参数 在JVM里有几个比较核心的参数,今天就主要来讲这几个: -Xms:JVM初始堆内存大小-Xmx:JVM堆内存的最大值-Xmn:JVM中新生代大小-XX:PermSize:永久代大小-XX:MaxPermSize:永久代最大…

拓世科技集团到访考察吉安青原区:共谋AIGC数字经济产业园发展大计

千帆竞发立潮头,奋勇争先谋发展,在中国这片广袤的大地上,先行者的每一次拓进都是历史的华章,远谋者的每一次交汇都是未来的预言。当红色江西大地与现代科技脉搏共振,当青原区的绿意拥抱拓世科技的AIGC科技,…

Mysql高级——索引

索引 索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足 特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构 上…

视频接口冷知识

常用视频接口的分辨率和带宽 VGA接口:VGA接口是一种传输模拟信号的视频接口,它只能支持视频传输,不支持音频传输。VGA接口的最大支持分辨率是2048x1536px。HDMI接口:HDMI接口是一种传输数字信号的视频接口,它可以同时…

【基于Cocos Creator 3.5的赛车游戏】8.引入触摸屏幕事件并简单的控制小车

转载知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具 项目地址:赛车小游戏-基于Cocos Creator 3.5版本实现: 课程的源码,基于Cocos Creator 3.5版本实现 上一张您已经对Cocos的坐标系有了了解。这一章我们将让小车能…

MFC-GetAdaptersAddresses获取网卡信息

需要:#pragma comment(lib, "IPHLPAPI.lib") GetAdaptersAddresses函数参数说明 ULONG bufferSize = 0;ULONG result = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize);/*参数1:ULONG Family 网络协议族,此参…

【linux】Linux wps字体缺失、加粗乱码解决

解决wps字体缺失问题 1、下载字体包 git clone https://github.com/iamdh4/ttf-wps-fonts.git2、创建单独放置字体的目录 mkdir /usr/share/fonts/wps-fonts3、复制字体到系统目录下 cp ttf-wps-fonts/* /usr/share/fonts/wps-fonts4、修改字体权限 chmod 644 /usr/share/f…

2023年Java毕业设计选题推荐,1000道创新创意Java毕业设计题目推荐,避免踩坑

大家好,我是程序员徐师兄,最近有很多同学咨询,说毕业设计了,不知道选怎么题目好,有哪些是想需要注意的。 确实毕设选题实际上对很多同学来说一个大坑, 每年挖坑给自己跳的人太多太多。选到合适的题目的话&…

python pycharm 下载 安装 (1)

pycharm 官网 JetBrains: 软件开发者和团队的必备工具 python 官网 Python Release Python 3.11.5 | Python.org 软件安装 pycharm python 终端安装 然后进行全局配置 打开pycahrm 可以在扩展里边搜索中文翻译 测试