n5.树(中)

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);//出队一个节点,返回给Tprintf("%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.mzph.cn/diannao/10468.shtml

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

相关文章

点云体积计算方法之一 附python代码

一句话描述思路:通过统计计算点云所占用的体素的数量来计算点云的近似体积。这是一个粗略的近似值,对于复杂的形状可能不准确。 另外需要注意,这个只适合点云密集分布的场景来计算体积,比如树木扫描的体积;如果只是有表面积扫描的点云,该方法就不能计算整个物体的体积了…

飞跨电容型的三电平(FC-NPC)逆变器simulink仿真模型

本人搭建了飞跨电容型的三电平逆变器simulink仿真模型&#xff0c;相较于二极管钳位型三电平逆变器而言&#xff0c;钳位二极管变为飞跨的电容。采用SPWM调制和均流均压控制&#xff0c;通过搭建仿真模型得到三电平波形。 三电平拓扑中的飞跨电容是指在电路的输出端使用电容来实…

书生作业:LMDeploy

自己随便说几句。 关于模型部署&#xff0c;很有趣的一件事就是&#xff0c;它一路随着深度学习训练一起发展&#xff0c;尽管例如tensorrt等工具的出现&#xff0c;不断试图降低部署门槛&#xff0c;但是实际上&#xff0c;每一次AI的升级&#xff0c;似乎让这个细分领域没有…

C++面向对象

面向对象的三大特征 封装 目的:隐藏实现细节,实现模块化。特性: 访问权限 public:对所有对象开放。protected:对子类开放。private:只对自己开放。可以通过友元类打破 private 限定。对属性和方法进行限定。class A {friend class B; // B 可以访问 c public:int a;void …

图片格式不对怎么转换?推荐几个图片转换的高效处理方法

在日常使用电脑或处理图片的过程中&#xff0c;我们经常会遇到图片格式不兼容的问题&#xff0c;例如&#xff0c;我们可能收到了一个无法打开的图片文件&#xff0c;或者想将图片转换为其他格式以便在不同的应用程序中使用&#xff0c;这时候就需要将图片转格式&#xff0c;所…

如何让组织充满活力?你需要做好这七步

组织活力&#xff0c;通俗点说就是&#xff1a; 从竞争对手角度看&#xff0c;组织活力强的组织能做到竞争对手做不到的事情&#xff1b; 从客户角度看&#xff0c;组织活力强的组织&#xff0c;客户感受好&#xff1b; 从员工角度看&#xff0c;组织活力强的组织&#xff0c…

salesforce inactive user 和 deactived user 的区别

在Salesforce中&#xff0c;“inactive user”和“deactivated user”都指的是不再活跃或被停用的用户&#xff0c;但它们在某些情况下可能有不同的含义。 Inactive User&#xff08;非活跃用户&#xff09;&#xff1a;一个用户被标记为“非活跃”时&#xff0c;通常是因为他们…

算法题① —— 数组专栏

1. 滑动窗口 1.1 长度最小的子数组 力扣&#xff1a;https://leetcode.cn/problems/minimum-size-subarray-sum/description/ int minSubArrayLen(int s, vector<int>& nums) {int result INT32_MAX; int sum 0; // 子序列的数值之和int subLength 0; // 子序列…

基于单片机的直流电机检测与控制系统

摘要&#xff1a; 文章设计一款流电机控制系统&#xff0c;以 STC89C51 作为直流电机控制系统的主控制器&#xff0c;采用 LM293 做为驱动器实现 对直流电机的驱动&#xff0c;采用霍尔实现对直流电机速度的检测&#xff1b;本文对直流电机控制系统功能分析&#xff0c;选择确…

WAAP全站防护理念,发现和保护敏感数据

数据是现代企业的新石油&#xff1a;正确使用它可以促进公司的发展并帮助企业在竞争中领先。就像石油一样&#xff0c;原始数据和未被发现的数据是毫无用处的&#xff0c;企业将无法从中受益&#xff1b;在最坏的情况下&#xff0c;它可能会导致安全事件。这也是企业投资敏感数…

巩固学习4

python中函数逆置的几种方法 s input()for i in range(len(s)-1,-1,-1):#从最后一位开始&#xff0c;步长为-1print(s[i],end)用for语句循环逆置 s input() s list(s) n len(s) for i in range(n//2):s[i],s[n-1-i] s[n-1-i],s[i]#从中间反转字符串 res "".j…

A计算机上的程序与B计算机上部署的vmware上的虚拟机的程序通讯 如何配置?

环境&#xff1a; 在A计算机上运行着Debian11.3 Linux操作系统&#xff1b;在B计算机上运行着Windows10操作系统&#xff0c;并且安装了VMware软件&#xff0c;然后在VMware上创建了虚拟机C并安装了CentOS 6操作系统 需求&#xff1a; 现在A计算机上的程序需要同虚拟机C上的软…

(十二)JSP教程——exception对象

exception对象用来发现、捕获和处理JSP页面中的异常&#xff0c;是JSP文件运行时产生的异常对象。如果要使用它&#xff0c;必须将对应的JSP的page指令的isErrorPage属性设置为ture&#xff0c;即&#xff1a;<% page isErrorPage”true”%>。 JSP文件在运行中有异常现象…

【负载均衡式在线OJ项目day6】源文件路由功能及文件版题库构建

一.前言 前文讲到了OJ模块的设计思路&#xff0c;毫无疑问这是一个网络服务&#xff0c;我们先使用httplib&#xff0c;将源文件的路由功能实现&#xff0c;先把框架写好&#xff0c;后续再更改回调方法。 随后计划编写Modify模块&#xff0c;提供增删查改题库的功能(主要是查…

【贪心算法】最小生成树Kruskal算法Python实现

文章目录 [toc]问题描述最小生成树的性质证明 Kruskal算法Python实现时间复杂性 问题描述 设 G ( V , E ) G (V , E) G(V,E)是无向连通带权图&#xff0c; E E E中每条边 ( v , w ) (v , w) (v,w)的权为 c [ v ] [ w ] c[v][w] c[v][w]如果 G G G的一个子图 G ′ G^{} G′是…

acer笔记本怎样进行系统还原?教你两招!

acer笔记本怎样进行系统还原&#xff1f;教你两招&#xff01; 作为笔记本用户&#xff0c;你在日常使用中可能会遇到各种各样的电脑问题。一般来说&#xff0c;对于一些小问题&#xff0c;我们可以通过一些简单的操作来解决&#xff0c;比如重新启动电脑或者长按电源键强制关机…

深入探讨布隆过滤器算法:高效的数据查找与去重工具

在处理海量数据时&#xff0c;我们经常需要快速地进行数据查找和去重操作。然而&#xff0c;传统的数据结构可能无法满足这些需求&#xff0c;特别是在数据量巨大的情况下。在这种情况下&#xff0c;布隆过滤器&#xff08;Bloom Filter&#xff09;算法就显得尤为重要和有效。…

MongoDB聚合运算符:$toLong

MongoDB聚合运算符&#xff1a;$toLong 文章目录 MongoDB聚合运算符&#xff1a;$toLong语法使用举例 $toLong聚合运算符将指定的值转换为长整数类型。如果指定的值为空或缺失&#xff0c;则返回null&#xff1b;如果值无法被转换为长整数&#xff0c;则报错。 语法 {$toLong:…

提高静态住宅代理稳定性妙招

在数字化时代的浪潮中&#xff0c;静态住宅代理因其独特的优势&#xff0c;如固定的IP地址、更高的隐私保护性等&#xff0c;逐渐成为网络爬虫、数据分析等领域不可或缺的工具。然而&#xff0c;静态住宅代理的稳定性问题一直是用户关注的焦点。本文将为您揭示提高静态住宅代理…

docker compose kafka集群部署

kafka集群部署 目录 部署zookeeper准备工作2、部署kafka准备工作3、编辑docker-compose.yml文件4、启动服务5、测试kafka6、web监控管理 部署zookeeper准备工作 mkdir data/zookeeper-{1,2,3}/{data,datalog,logs,conf} -p cat >data/zookeeper-1/conf/zoo.cfg<<EOF…