【数据结构】二叉树的链式结构及实现

news2024/12/23 23:38:18

目录

1. 前置说明

2. 二叉树的遍历

2.1 前序、中序以及后序遍历

2.2 层序遍历

3. 节点个数及高度等

4. 二叉树的创建和销毁


1. 前置说明

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

BTNode* CreatBinaryTree()
{
	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;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是

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

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

2. 二叉树的遍历

2.1 前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

// 二叉树前序遍历
void PrevOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->val);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->val);
	InOrder(root->right);
}

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->val);
}

下面主要分析前序递归遍历,中序与后序图解类似,大家可自己动手绘制。

前序遍历递归图解:

前序遍历结果:1 2 3 4 5 6

中序遍历结果:3 2 1 5 4 6

后序遍历结果:3 2 5 6 4 1

2.2 层序遍历

层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

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

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

	QueueDestroy(&q);
}

3. 节点个数及高度等

// 二叉树节点个数
int TreeSize(BTNode* root);
// 二叉树叶子节点个数
int TreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int TreeKLevel(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, int x);
// 二叉树的高度
int TreeHeight(BTNode* root);
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 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);
}

int TreeKLevel(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}

BTNode* TreeFind(BTNode* root, int x)
{
	if (root == NULL)
		return NULL;
	if (root->val == x)
		return root;

	BTNode* ret = NULL;
	ret = TreeFind(root->left, x);
	if (ret)
		return ret;
	ret = TreeFind(root->right, x);
	if (ret)
		return ret;

	return NULL;
}

int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

4. 二叉树的创建和销毁

// 手动构建二叉树
BTNode* BuyNode(int x);
// 二叉树销毁
void TreeDestroy(BTNode* root);
// 判断二叉树是否是完全二叉树
int TreeComplete(BTNode* root);
BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	node->val = x;
	node->left = NULL;
	node->right = NULL;
	return node;
}

void TreeDestroy(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestroy(root->left);
	TreeDestroy(root->right);
	free(root);
}

int TreeComplete(BTNode* root)
{
	Que q;
	QueueInit(&q);

	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		if (front == NULL)
			break;
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
		QueuePop(&q);
	}
	// 已经遇到空节点,如果队列中后面的节点还有非空,就不是完全二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

本文完

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

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

相关文章

不用for循环,巧妙自动翻页获取所有数据

1、设置while循环的标记条件; 2、设置初始页码; 3、防止无限循环,设置最大循环次数为1000次; 4、当页码为第一次时,获取数据,并获取一共有多少页,并更新最大页码; 5、页码自动加…

FPGA面试题(4)(跨时钟域处理)

跨时钟域处理方法 慢->快快->慢单bit在快时钟域同步打拍,将信号同步到快时钟域展宽后同步打拍多bit异步FIFO异步FIFO握手信号 一.打两拍 适用于单bit跨时钟域处理所谓的打两拍就是定义两级寄存器实现延时 那为什么是打两拍,不是打一拍&#x…

方案:餐厅饭店AI智能视频监控可视化监管系统搭建方案

随着大众对食品卫生的要求逐渐提升,明厨亮灶已成为很多人选择就餐点的一大要求,明厨亮灶的产生对保障大众食安起到了十分显著的作用,后厨作为食品安全重要场所,需要“亮”出来,前厅也同时需要监控系统的保护&#xff0…

获取当日n个季度前的日期所处季度的最后一天——时间相关函数4

本文介绍的函数用于获取当日n个季度前的日期所处季度的最后一天(有点绕,看后面例子就好理解了)。 源码 def last_day_of_quarter_before_n_quarters(n):"""获取当日n个季度前的日期所处季度的最后一天:return: 当日n个季度前…

这才叫良心软件!

今年以来,大模型相关的技术究竟有多火,不用多说,相信大家心中也已有答案。 自GPT-4发布以来,各大互联网大厂都坐不住了,纷纷推出自己的大模型产品。 前段时间,“科大讯飞版”的 ChatGPT 正式上线了&#…

uniapp pc端和移动端列表上拉刷新加载分页

效果图&#xff1a; tips: 实现了pc端和移动端兼容 代码实现&#xff1a; html: <view v-if"answerList.length > 1" style"padding:30rpx 0;color:#888;text-align: center;"><view>{{loadMore}}</view> </view>data: …

一键切换IP地址:电脑IP更改的简便方法

今天我要和大家分享一个电脑IP更改的简便方法——一键切换IP地址。如果您想要更改电脑的IP地址&#xff0c;无需繁琐的设置和复杂的步骤&#xff0c;只需使用以下简单的方法&#xff0c;即可轻松实现IP地址的切换。让我们开始吧&#xff01; 1、使用批处理脚本 批处理脚本是一…

如何在使用JetBrains IDE时文本编辑更高效?这个IdeaVim好用

IdeaVim 插件已经发布一段时间了&#xff0c;它帮助开发者利用 Vim 的强大功能扩展 JetBrains IDE。JetBrains 内部有一个专属团队维护此插件&#xff0c;这为您提供了两项优势&#xff1a;以键盘为中心的编辑器和 IDE 的支持。 获取JetBrains IDE新版下载 Vim为文本中的跳转…

伦敦金的交易时间究竟多长?

接触过伦敦金交易的投资者&#xff0c;应该都知道自己根本不用担心市场上没有交易的机会&#xff0c;因为它全天的交易时间长达20多个小时&#xff0c;也就是在每一个正常的交易日&#xff0c;除去交易平台中途短暂的系统维护时间&#xff0c;投资者几乎全天都可以做盘。 伦敦金…

银河麒麟 ARM 架构 离线安装Docker

1. 下载对应的安装包 进入此地址下载对应的docker 离线安装包 下载地址 将文件上传到服务器 解压此文件 tar zxf docker-18.09.1.tgz将 docker 相关命令拷贝到 /usr/bin&#xff0c;方便直接运行命令 cp docker/* /usr/bin/启动Docker守护程序 dockerd &验证是否安装成…

苹果ipad触控笔哪个好?ipad手写笔推荐

在现在&#xff0c;电容笔已经成为了iPad的一个重要配件&#xff0c;随着其的功能变得更加强大&#xff0c;更多的人开始使用电容笔。因此&#xff0c;如何挑选出一款性价比高、功能优秀的电容笔&#xff0c;是大家最关心的事情。那么&#xff0c;哪一款电容笔更实惠&#xff0…

应对广告虚假流量,app广告变现该如何风控?

移动广告市场中的虚假流量一直是困扰各移动应用厂商的难题&#xff0c;广告作为app商业化变现最为直接快捷的途径&#xff0c;也引申出了流量作弊与反作弊的纷争。 根据《2021中国异常流量报告》&#xff0c;2021年中国品牌广告市场因异常流量造成的损失约为326亿人民币&#…

计算机网络传输层知识总结·

传输层提供的服务 传输层的功能 ●传输层提供进程之间的逻辑通信&#xff0c;即端到端的通信 ●复用和分用 ●差错检测&#xff08;首部和数据部分&#xff09; ●面向连接的TCP和无连接的UDP 端口的作用 ●端口标识的是主机中的进程 ●硬件端口是不同…

早安问候语早安心语,别把人生想太难,人生需要鼓励

1、别把人生想的太难&#xff0c;人生需要几分自我的鼓励&#xff0c;不管在什么时候&#xff0c;要有几分信念和信心&#xff0c;生活少不了哭哭笑笑。青山绿水依然在&#xff0c;来来往往人不同&#xff0c;要学会看得惯&#xff0c;还要学会看得开&#xff0c;你内心的平坦是…

开源酒店预订订房小程序源码系统+多元商户 前端+后端完整搭建教程 可二次开发

大家好啊&#xff0c;罗峰今天来给大家分享一款酒店预订订房小程序源码系统&#xff0c;这款系统进行了全新的升级&#xff0c;从原来的单门店升级成了多门店&#xff0c;可以自由切换账号&#xff0c;统一管理。功能强大。以下是部分代码截图&#xff1a; 酒店预订订房小程序源…

性价比高的学生用台灯?这些Led台灯适合学生用

想要选好护眼台灯首先我们要知道什么是护眼台灯&#xff0c;大的方向来看&#xff0c;护眼台灯就是可以保护视力的台灯&#xff0c;深入些讲就是具备让灯发出接近自然光特性的光线&#xff0c;同时光线不会伤害人眼而出现造成眼部不适甚至是视力降低的照明设备。 从细节上看就…

人物——高会军

近日&#xff0c;美国电气与电子工程师协会&#xff08;英文简称IEEE&#xff09;系统、人与控制论学会在美国夏威夷公布2023年诺伯特维纳奖&#xff08;Norbert Wiener Award&#xff09;获奖者&#xff0c;中国自动化学会会士、副秘书长&#xff0c;欧洲科学院院士&#xff0…

施耐德PLC之间的的无线MODBUS通信实例

本文主要介绍施耐德&#xff08;睿易&#xff09;PLC之间的MODBUS通讯的具体操作和各参数的意义&#xff0c;此方案可以作为施耐德&#xff08;睿易&#xff09;PLC之间的的无线MODBUS 通信实例。在本方案中采用了西门子、施耐德等欧美系PLC专用无线通讯终端DTD434M&#xff0c…

【python】求多变量/样本(矩阵)之间的相关性系数

创作日志&#xff1a; Pearson或Spearson代表的是两个变量之间的相关性&#xff0c;因此一般输入是两个向量(vector)&#xff0c;那么当我们有多个变量时&#xff0c;怎样计算他们两两之间的相关性系数呢&#xff1f;得到的correlation matrix各元素代表的又是什么意思呢&#…

1800*C. Table Decorations(贪心 || 二分)

Problem - 478C - Codeforces 解析&#xff1a; 做法一&#xff1a;二分&#xff0c;显然左右边界为 0 和 总数量除以3。check时mid&#xff0c;任意两项之和都不能小于mid 做法二&#xff1a;贪心&#xff0c;当数量最大的气球数量的一半小于另外两种颜色气球的数量之和&#…