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.hqwc.cn/news/689345.html

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

相关文章

更适合户外使用的开放式耳机,佩戴舒适音质悦耳,虹觅HOLME NEO体验

随着气温的逐渐升高&#xff0c;不管是在室内工作娱乐&#xff0c;还是到户外运动健身&#xff0c;戴上一款合适的耳机都会帮我们隔绝燥热与烦闷&#xff0c;享受音乐与生活。现在市面上的耳机类型特别多&#xff0c;我很喜欢那种分体式的开放耳机&#xff0c;感觉这种耳机设计…

关于各类软件下载及使用

文章目录 一、VS Code1、下载2、安装3、使用 二、Dev-C1、下载2、安装3、使用 三、VS20191、下载2、安装3、使用 四、IDEA1、下载2、安装3、使用 五、Fiddler1、下载1.1 官网下载1.2 文件下载 2、安装3、使用 一、VS Code 1、下载 2、安装 3、使用 二、Dev-C 1、下载 2、…

Centos7安装图形化界面

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; Centos7安装图形化界面https://myweb.myskillstree.cn/43.html 目录 一、安装GNOME桌面 二、开机自启动修改为命令行模式 三、卸载图形化界面 一、安装GN…

JavaScript 动态网页实例 —— 事件处理应用

前言 事件处理的应用很广泛。在事件处理的应用中,鼠标事件的应用是最常用到的。本章给出几个鼠标事件处理应用的示例,包括:页面预览、图像切换、点亮文本、鼠标跟随、鼠标感应和禁用鼠标按键。在这些示例中,有的可以直接拿来应用,有的则只提供了一种应用的方法,稍加拓展,…

【计算机网络】数据链路层的功能

数据链路层的基本功能&#xff1a; 封装成帧透明传输差错检测 数据链路层使用的信道主要有两种 点对点信道——PPP协议广播信道——CSMA/CD协议(有线局域网)、CSMA/CA协议(无线局域网) 数据链路层所处的地位 从图中可以看出&#xff0c;数据从主机H1送到主机H2需要在路径中…

使用 sudo apt upgrade 出现的提示

┌────────────────────────────────────────────────┤ Pending kernel upgrade ├────────────────────────────────────────────────┐ │ …

vue3+TS或JS, 实现粒子特效 @tsparticles/vue3

在跟着B站视频BV11s4y1a71T学习时&#xff0c;使用到了粒子效果&#xff0c;但是以下这种情况只适用于项目是基于typescript的写法&#xff0c;否则无法实现。 粒子效果 VUE3TStsparticles/vue31、安装2、main.ts 引入3、App.vue4、效果 VUE3JS非最新版1、安装低版本的vue3-pa…

ACC-UNet: A Completely Convolutional UNet Model for the 2020s

文章目录 ACC-UNet: A Completely Convolutional UNet Model for the 2020s摘要方法实验结果 ACC-UNet: A Completely Convolutional UNet Model for the 2020s 摘要 这十年以来&#xff0c;计算机视觉领域引入了 Vision Transformer&#xff0c;标志着广泛的计算机视觉发生了…

同程旅行基于Proxy的Kafka最佳实践

公众号文章&#xff1a;同程旅行基于Proxy的Kafka最佳实践 Apache Kafka&#xff0c;作为当前企业级数据流处理的首选平台&#xff0c;由于其高吞吐量和可扩展性而深受欢迎。 然而&#xff0c;随着企业数据量的爆炸性增长和业务需求的多样化&#xff0c;Kafka 集群面临着各种挑…

模型 空船效应

1 空船效应的应用 1.1 空船效应帮助客户服务人员面对挑战性客户 赵敏是一家大型电信公司的客户服务经理。在一次服务中&#xff0c;一位客户因为网络连接问题而非常愤怒&#xff0c;他通过电话对赵敏大声抱怨&#xff0c;并要求立即解决问题。一般在这种情况下&#xff0c;客…

暗区突围哪里获得测试资格 暗区突围测试资格获取方法

在游戏业界的浩瀚星空中&#xff0c;《暗区突围》如同一颗璀璨新星&#xff0c;以其独树一帜的游戏模式和前所未有的沉浸式体验&#xff0c;迅速吸引了全球玩家的目光。它不仅仅是一款游戏&#xff0c;更像是一次对勇气、智慧与团队合作的深度探索。玩家在危机四伏的暗区中&…

IP地址127.0.0.1的误解:一次投标监管的技术失误

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …