n5.树(中)

news2024/11/18 2:43:46

1、二叉树的遍历

1.1先序、中序、后序遍历

先序遍历

根->左->右
在这里插入图片描述

先序遍历先访问根节点,再访问它的左子树,然后访问它的右子树。对于每次访问到的结点,都要递归地访问左子树、后右子树———递归
创建

typedef struct TreeNode* BinTree;
struct TreeNode {
	int Data;
	BinTree Left;
	BinTree Right;
};
void PreOrderTraversal(BinTree BT)
{//先看树空不空,如果是空的退出函数
	if(BT)
	{
		printf("%d",BT->Data);//先根节点
		PreOrderTraversal(BT->Left);//再左子树
		PreOrderTraversal(BT->Right);//后右子树
	}
}

在这里插入图片描述

遍历的顺序就是ABDFECGHI

中序遍历

左->根->右

void InOrderTraversal(BinTree BT)
{
	if( BT )
	{
		InOrderTraversal(BT->Left);//先左子树
		printf("%d",BT->Data);//再根节点
		InOrderTraversal(BT->Right);//后右子树
	}
}

在这里插入图片描述

先将左半B部分打印出来,再打印A,再打印右半C部分。在B部分这边,先打印D部分,再打印F部分。在D部分这边…依次先对左递归,再中,再右边。

后序遍历

左->右->根

void InOrderTraversal(BinTree BT)
{
	if( BT )
	{
		InOrderTraversal(BT->Left);//先左子树
		InOrderTraversal(BT->Right);//再右子树
		printf("%d",BT->Data);//再根节点
	}
}

在这里插入图片描述

每到一个新的节点,都是先左:先左下去;再回来:再右;

三个遍历都是先左后右,先序(根左右)、中序(左根右)、后序(左右根)说的是根的位置;->先序遍历根节点在第一个;后序遍历根节点在最后一个。

中序遍历非递归遍历算法

在这里插入图片描述

按照一个整体的路线进行堆栈的操作。按照左->中->右的顺序,碰到一个节点就放入堆栈,向左边走,左边走到底,返回的时候就抛出结点;然后往右边走…

void InOrderTraversal( BinTree BT )
{
	BinTree T = BT;
	Stack S = CreatStrack( Maxsize );//创建一个堆栈
	while(T || !IsEmpty(S) )//当其中之一不空的时候(循环到树T和堆栈S全都为空为止)
	{
		while(T)//当T存在,循环到T为NULL
		{
			Push(T);//先将非空的T压入栈
			T = T->Left;//继续向左边走
		}
		if( !IsEmpty(S) )//如果堆栈还存在节点
		{	
			T = Pop(S); printf("%d",T->Data);//弹出堆栈并访问打印
			T = T->Right;//第一次内循环结束,以右子树为新起点开启新一轮循环。判断外循环条件。
		}
	}
}

第一次碰到的时候push进去,第二次碰到的时候Pop出去。

1.2层序遍历

二叉树遍历的核心就是把二维的结构线性化,变成一个一维的线性序列的过程。在访问过程中,都是从一个节点开始访问,通过这个节点访问他的左右儿子。访问它的左儿子的时候,通过这个左儿子又开始访问子节点…由于访问节点只能通过父节点来访问,从这个结点访问到了左节点,那么右儿子怎么办?那么就需要保存这个父节点(或者保存右儿子),就能够再访问右儿子。
在这里插入图片描述

队列实现

在这里插入图片描述
在这里插入图片描述

先让根节点入队,开始循环操作:根节点出队,把他的左右儿子入队;继续出队队列中的下一个节点,把他的左右儿子入队;继续出队下一个节点,把他的左右儿子入队…这样就会完成遍历。
特征:一层一层遍历,循环“出队,入队他的左右节点”

在这里插入图片描述

void LevelOrderTraversal( BinTree BT )
{
	Queue Q;//队列
	BinTree T;//树
	if( !BT ) return;
	else
	{
		Q = CreatQueue(MaxSize);
		AddQ(Q,BT);//将根节点入队,开始循环的时候一定是不空的
		while( !IsEmptyQ( Q ) )//
		{//循环做三件事情:一个出队,并将他的左右节点入队
			T = DeleteQ(Q);//出队一个节点,返回给T
			printf("%d",T->Data);//访问
			//添加它的左右节点:(注意判断是否存在)
			if(T->Left) AddQ(Q,T->Left);
			if(T->Right) AddQ(Q,T->Right);
			
		}
	}
}

1.3遍历的应用例子

输出二叉树中的叶子结点

基于前序遍历输出:

void PreOrderTraversal( BinTree BT)
{
	if( BT )
	{//基于前序遍历,只是增加一个判断条件
		if( !BT->Left && !BT->Right )
		{
			print("%d",BT->Data);
		}
		PreOrderTraversal( BT->Left);
		PreOrderTraversal( BT->Right);
	}
}

求二叉树的高度

树是递归定义的,以递归来实现:一个树的高度 = 左右子树最大高度 + 1 ,所以必须知道左右两个子树的高度,才能求出它的高度。
所以基于后序遍历来实现

int PostOrderGetHeight( BinTree BT )
{
	if( !BT ) return 0 ;//不存在的情况
	else 
	{
		HL = PostOrderGetHeight(BT->Right);//递归左子树的深度;
		HR = PostOrderGetHeight(BT->Right);//递归右子树的深度;
		MaxH = (HL > HR)? HL : HR ;//条件表达式找出最大深度
		return (MaxH + 1);
	}
}

二元运算表达式树 及其遍历

在这里插入图片描述

叶节点都是运算数,非叶结点都是都是运算符号。
三种遍历方式可以得到三种不同的表达式:
在这里插入图片描述

其中,中缀表达式会受到运算符优先级的影响(不准确)

两种遍历序列确定二叉树

根是容易确定的,先序遍历的第一个结点就是根;后序遍历的最后一个节点就是根。只能由先序/后序 + 中序才能唯一的确定一个二叉树。
------->先序+中序:
在这里插入图片描述

  • 先由先序序列第一个节点确定根节点
  • 在中序序列找到根节点,那么这个根节点就将中序序列分割成先序遍历的左子树先序遍历的右子树
  • 在先序序列的根节点向后找到先序遍历的左子树先序序列的右子树
  • 那么就分别得到了先序序列和中序序列的左右子树,重复操作。
    在这里插入图片描述

2.二叉树的同构

在这里插入图片描述
表示方式:
使用结构数组的方式每个数组单元包括char类型的节点名称、左子树对应的下标、右子树对应的下标。下标从0开始。
在这里插入图片描述

3.二叉搜索树

在这里插入图片描述

对于任何节点,其左子树中的所有节点的值都小于该节点的值,而右子树中的所有节点的值都大于该节点的值。
保持二叉搜索树的前提是保证它的有序性

3.1查找功能

静态查找:查找的元素是不动的,在一个集合上主要是Find操作,没有插入与删除。二分查找是一个很好的方法;
动态查找:除了Find,还有插入与删除的操作;
二叉搜索树:左子树 < 根节点 < 右子树
主要的功能函数:
在这里插入图片描述

查找特定值

在这里插入图片描述

BnTree Find(int x,BinTree BST)
 {
 	if(BST == NULL) return NULL;//二叉树为空,直接返回
 	if(x < BST->Data)
 	{
 		return Find(x,BST->Left);//注意要有返回值,一定要是return,在左子树中继续查找
 	}
 	else if(x > BST->Data)
 	{
 		return Find(x,BST->Right);//再右子树中继续查找
 	}
 	else return BST;//剩下的情况就是x == BTS->Data
 }

以上代码是通过尾递归(在程序return时递归)的方式实现的,效率不是很高;可以将尾递归函数改为迭代函数,即尾递归可以用循环来实现

BinTree Find(int x,BinTree BST)
{
	if(BST == NULL)  return NULL;//空二叉树
	BinTree Temp = BST;
	while(Temp)
	{//当Temp存在的时候执行:
		if(x > Temp->Data) Temp = Temp->Right;
		else if(x < Temp->Data) Temp = Temp->Left;
		else return Temp; //x == Temp的情况
	}
	return NULL;//找不到,二叉树中不存在x
}

查找的效率取决于树的高度

最大查找和最小查找

由于二叉树从根节点开始,向左Data值一直减小,向右Data值一直增大,故可以得出最小Data值在最深层的左子树节点,最大Data值在最深层的右子树节点。
可以确定的是,最大/最小结点一定不是具有两个儿子的节点
在这里插入图片描述

既可以通过递归实现,也可以通过循环实现

  • 循环算法:
BinTree FindMin(BinTree BST)
{
	BinTree Temp = BST;
	if(Temp)//这个if语句主要是针对Temp是否存在
	{
		while(Temp->Left)
		{//当左子树存在的时候,一直向左边走
			Temp = Temp->Left; 
		}
	}
	return Temp;//这里对BST为空的时候也适用
}
  • 递归算法:
BinTree Temp = BTS;
BinTree FindMax(Temp)
{
	if( Temp == NULL) return NULL;//这个主要用于首次判断
	//递归部分:
	else if(Temp->Right)
	{
		return FindMax(Temp->Right);//大都返回函数
	}//当递归到了Temp没有右子树的时候,此时的Temp就是所找的最深的右子树
	else return Temp;//最后返回指针,回溯
}

二叉搜索树的插入*

在这里插入图片描述

在理解递归的时候,形式参数BTS、函数体内部的BTS就可以理解为在递归过程中具体的树节点

BinTree Insert(int x,BinTree BST)//函数通过返回节点来实现赋值(插入)操作
{
	if( !BST )//递归到参数结点为空的时候
	{
		//因为是空的,所以申请空间完成赋值
		BinTree BST = malloc(sizeof(struct TreeNode));
		BST->Data = x;
		BST->Left = BST->Right = NULL;
	}
	else if(x < BST->Data)//x小于此节点,向左	
	{
		BST->Left = Insert(x,BST->Left);
	}
	else if(x > BST->Data)//继续向右
	{
		BST->Right = Insert(x,BST->Right);
	}
	/*else  x = BST->Data,表示X已经存在,不用操作*/
	return BST;//这里BST是抽象的形式参数,返回的指针取决于传入的BST具体是什么
}

在这里插入图片描述

函数的出口只有一个return BST;,无论是创造一个新节点还是BST->Right = Insert(x,33->Right);每次Insert函数最后都会返回某个具体的节点;
eg,当递归到了叶节点33,还差一步即将完成插入35操作。叶节点33存在,首先33号->Data < 35,那么就将35继续向右走下去,执行33->Right = Insert(x,33->Right);因为33->RIght == NULL,所以就意味着要为33号结点创建一个右节点并且将35储存到这里,Insert()函数执行完毕之后就创建了一个新节点,并且把储存了35的右节点返回给33->Right,这就完成了插入操作。之后就层层递归返回,直至真正的BST返回到首次Insert函数,完成整个递归过程。

  • 当Insert函数的BST参数为NULL时,意味着已经到达了应该插入新节点的位置。
  • 整个过程是递归的,每一步都是重复决策的过程:比较当前节点的值,并根据比较结果向左或向右移动,直到找到一个空位置来插入新节点。
  • 其中的有效赋值只是将x进行赋值,其他赋值都是重复赋值,例如BST->Right = BST->Right(函数的返回值);
  • return BST;这里BST是抽象的形式参数,形式参数是啥最后就会返回啥,如果一个节点不空,当递归回溯的时候,这一步还是返回此节点指针。

二叉搜索树的删除

要实现删除操作,需要先找到目标节点(要删除的节点),然后执行操作。
目标结点分为几种:

  1. 叶节点:直接删除就好
  2. 只有左儿子/右儿子的结点:把已删除结点的儿子连接到上一层
  3. 既有左儿子也有右儿子的节点
    在这里插入图片描述

这种情况有些复杂,需要转化问题。有两种思路:一种是将目标节点用右子树的最小节点替代;另一种方法是用左子树中的最大节点替代
在右子树中找一个最小值,一定在右子树中的最左边;左子树中的最大值,一定在左子树的最右边。
在这里插入图片描述

  1. 首先通过查找找到41号节点
  2. 在41号结点的左右子树再次寻找,进行替代删除;
  3. 41号结点为删除50号(使用查找的方法找到右子树的最小值),并且把41号节点的值赋值为50;
  4. 改删除41号节点为删除35号(使用查找的方法找到),并且把41号结点的值赋值为35,并将34连接到上一层。
    因为转化成删除最大/最小节点一定不会有两个儿字节点,所以把这种情况转化为前两种情况。
BinTree Delete(int x,BinTree BST)//注意返回类型是树节点
{
	BinTree Temp;
	if( !BST )//首先对传入的结点进行判断
		printf("要删除的结点未找到");
	//先找到目标节点(要删除的结点)
	else if(x < BST->Data)//x小,向左子树进行递归
		BST->Left = Delete(x,BST->Left);
	else if(x > BST->Data)
		BST->Right = Delete(x,BST->Right);
	else //那这个情况就是BST->Data == x,找到对应的目标节点 
	{//因为目标结点的类型不同,删除的操作也不同,首先进行目标结点类型的判断:
		if(BST->Right && BST->Left)//如果目标节点左右子树均存在,那么就属于最复杂的那种
		{//进行替代删除,这里就选择右子树的最小值进行替代删除:
		Temp = FindMin(BST->Right);//找到右子树中的最小节点
		BST->Data = Temp->Data;//将右子树中的最小节点的值赋值给目标节点
		BST->Right = Delete(Temp->Data,BST->Right);//在目标节点的右子树中删除这个替代节点Temp	
		}
		else//左右子树至少其一不存在
		{
			Temp = BST;//先保存一下
		//将子节点接到上一次层:
			if( !BST->Right)//当目标节点只有左节点或者是叶节点(叶节点两子树为空,那么BST = NULL 也就是叶节点直接删除)
				BST = BST->Left;
			else//目标节点只有右节点
				BST = BST->Right;
			free(Temp);//释放目标节点
		}
	}
	return BST;//当每次函数的以上程序执行完成,函数唯一出口。从目标节点开始,逐一向前回溯,最后返回整个树的根节点
}

易错题目:

  1. 若一搜索树(查找树)是一个有n个结点的完全二叉树,则该树的最大值一定在叶结点上
    基于完全二叉树的特点,他是完美二叉树的截肢部分,那么最深右子树最大结点上还可以挂个左子树,他还是最大节点,但是他不是叶节点。因为要求是搜索树,还要保证顺序性。
    2)若一搜索树(查找树)是一个有n个结点的完全二叉树,则该树的最小值一定在叶结点上

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

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

相关文章

理解导数(x^n求导后nx^n-1)

以下都是为了方便理解 微小量是 t M(x)是一个函数 M 在 x 处的斜率 M 在 x 处的导数 垂直距离 平移距离 M ( x t ) − M ( x ) ( x t ) − x M在x处的斜率 M在x处的导数 \dfrac{垂直距离}{平移距离} \dfrac{M\left( xt\right) -M\left( x\right) }{(x t) -x} M在x处的斜…

Tiff文件解析和PackBits解压缩

实现了Tiff图片文件格式的解析&#xff0c;对Tiff文件中的PackBits压缩格式进行解压缩&#xff0c;对Tiff文件中每一个Frame转换成BufferedImage显示。 Java语言实现&#xff0c;Eclipse下开发&#xff0c;AWT显示图片。 public static TIFF Parse(final byte[] bytes) throw…

618洗地机推荐,市面上各式各样的洗地机怎么选?这里有答案

洗地机的出现极大地改变了清洁方式&#xff0c;通过结合扫地、拖地、吸尘等多种功能&#xff0c;实现了一机多用的便捷清洁体验。而且洗地机不需要弯腰&#xff0c;每次也不用清洁很长时间&#xff0c;节省出来的时间可以更好的休息&#xff0c;但是市面上各式各样的洗地机怎么…

突破编程界限:探索AI编程新境界

文章目录 一、AI编程助手1.1 Baidu Comate智能代码助手1.2 阿里云 通义灵码 二、场景需求三、体验步骤3.1 官网下载3.2 手动下载 四、试用感受4.1 提示4.2 注释生成代码4.3 代码生成4.4 选中生成注释4.5 查看变更&新建文件4.6 调优建议4.7 插件使用 五、结尾推荐 一、AI编程…

代码审计-php篇之某CRM系统多处sql注入

&#x1f31f; ❤️ 作者&#xff1a;yueji0j1anke 首发于公号&#xff1a;剑客古月的安全屋 字数&#xff1a;3516 阅读时间: 35min 声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果…

Python爬虫 【1】 —— 爬虫基础

爬虫基本套路 基本流程 目标数据来源地址结构分析 具体数据在哪&#xff08;网站 还是APP&#xff09;如何展示的数据、 实现构思操刀编码 基本手段 破解请求限制 请求头设置&#xff0c;如&#xff1a;useragent为有效客户端控制请求频率&#xff08;根据实际情境&#xff09…

在Linux上安装并运行RabbitMQ

目录 准备CentOS服务器 下载rabbit-server和erlang文件 启动RabbitMQ服务 准备CentOS服务器 两个命令&#xff0c;选一个能用的&#xff0c;查看CentOS服务器的版本 lsb_release -a下载rabbit-server和erlang文件 参考文章&#xff1a;http://t.csdnimg.cn/t8BbM 1、创建新…

龟兔赛跑(基于GUI与多线程实现)

直击龟兔赛跑现场 下面这张图是我们设计龟兔赛跑界面的初始效果与基本组成结构&#xff1a; 接下来是我仅代表我个人提出的一些疑问与解答&#xff1a; 1、俩动物以图片的形式显示&#xff1f; 其实在这里两个动物类就像标签一样 标签组件是什么&#xff1f;用于短文本字符串…

对话易参创始人黄怡然:股权能不能赋能企业增长?| 极新企服直播实录

“ 致所有爱画饼的老板 ” 整理 | 云舒 编辑 | 小白 出品&#xff5c;极新 2022年以前&#xff0c;股权激励作为企业实现增长、吸引人才、保留人才并大幅度激发人才价值的重要手段&#xff0c;几乎成为每一个企业的标配。但是&#xff0c;现在这个时代&#xff0c;股权激励几…

2024年最新方法下载钉钉群直播回放

链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1234 --来自百度网盘超级会员V10的分享 1.首先解压好所有的压缩包&#xff0c;这个压缩包里面还套着一共逍遥一仙下载器压缩包&#xff0c;也解压 2.进入逍遥一仙下载器文件夹&#xff0c;打开M3U8 V1.4.8 0508.e…

ESP32-C3-MINI-1

https://www.espressif.com.cn/sites/default/files/documentation/esp32-c3-mini-1_datasheet_cn.pdf 芯片 https://files.seeedstudio.com/wiki/XIAO_WiFi/Resources/esp32-c3_datasheet.pdf 结果参考&#xff1a; https://blog.csdn.net/iamxxdd/article/details/12386419…

【回溯算法】【Python实现】最大团问题

文章目录 [toc]问题描述回溯算法Python实现时间复杂性 问题描述 给定无向图 G ( V , E ) G (V , E) G(V,E)&#xff0c;如果 U ⊆ V U \subseteq V U⊆V&#xff0c;且对任意 u u u&#xff0c; v ∈ U v \in U v∈U有 ( u , v ) ∈ E (u , v) \in E (u,v)∈E&#xff0c;则称…

XMind 2021 v11.1.2软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; XMind 2021 v11.1.2被誉为顶尖思维导图工具&#xff0c;以其简洁、整洁的界面和直观的功能布局脱颖而出。尽管软件体积小巧&#xff0c;却极具强大功…

【小红书采集软件】根据关键词批量爬取小红书笔记正文、笔记链接、发布时间、转评赞藏等

一、背景介绍 1.1 爬取目标 熟悉我的小伙伴可能了解&#xff0c;我之前开发过2款软件&#xff1a; 【GUI软件】小红书搜索结果批量采集&#xff0c;支持多个关键词同时抓取&#xff01; 【GUI软件】小红书详情数据批量采集&#xff0c;含笔记内容、转评赞藏等&#xff0c;支…

【初阶数据结构】单链表基础OJ题讲解

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL。 &#x1f4da;本文收录与初阶数据结构系列&#xff0c;本专栏主要是针对时间、空间复杂度&#xff0c;顺序表和链表、栈和队列、二叉树以及各类排序算法&#xff0c;持…

Coursera吴恩达深度学习专项课程01: Neural Networks and Deep Learning 学习笔记 Week 04 (完结)

Neural Networks and Deep Learning Course Certificate 本文是学习 https://www.coursera.org/learn/neural-networks-deep-learning 这门课的笔记 Course Intro 文章目录 Neural Networks and Deep LearningWeek 04: Deep Neural NetworksLearning Objectives Deep L-layer…

智能家居2 -- 实现网络控制模块

这一模块的思路和前面的语言控制模块很相似&#xff0c;差别只是调用TCP 去控制 废话少说&#xff0c;放码过来 增添/修改代码 socket_interface.c #include <pthread.h>#include "socket_interface.h" #include "control.h" #include "socke…

3分钟掌握Suno API!音痴也能创作热门曲!免费拥有个人爆款音乐!

Suno API 的申请及使用 随着 AI 的应用变广&#xff0c;各类 AI 程序已逐渐普及。AI 已逐渐深入到人们的工作生活方方面面。而 AI 涉及的行业也越来越多&#xff0c;从最初的写作&#xff0c;到医疗教育&#xff0c;再到现在的音乐。 Suno 是一个专业高质量的 AI 歌曲和音乐创…

系统代理开启时,钉钉页面加载失败等问题处理

若Windows端钉钉点击工作台/文件提示“页面加载失败”&#xff0c;可先将钉钉升级到7.1.10及以上版本&#xff1b;若依旧报错&#xff0c;可通过以下方法操作&#xff1a; 1、【电脑端钉钉】-【登录页面】-【切换到密码登录页面】-【网络设置】-切换为【不使用代理】&#xff…

示例七、超声波传感器测距

通过以下几个示例来具体展开学习,了解超声波传感器原理及特性&#xff0c;学习超声波传感器的应用&#xff1a; 示例七、超声波传感器测距 一、基本原理&#xff1a; 1、超声波测距仪的系统结构 利用超声测距原理测量物体之间的距离&#xff0c;当此距离小于某一设定值时&…