二叉树的遍历

news2024/11/15 4:30:41

二叉树的遍历

文章目录

  • 二叉树的遍历
    • •二叉树的遍历定义
    • • 二叉树的三种遍历方式
    • 先序遍历的递归算法
    • 中序和后序遍历的递归算法
    • 二叉树遍历的相关问题
      • ♥问题1
        • 解题模型
        • ▪算法构思:
        • ▪代码实现:
      • ♥问题2
        • 解题模型
        • 构建思路:
        • 代码如下:
      • ♥问题3
        • 算法构思:
        • 代码构建:
      • ♥问题4
        • 算法思路:
        • 解题模型:
        • 代码构建:

•二叉树的遍历定义

​ • 按照一定次序访问树中所有节点,并且每个节点仅被访问一次的过程.

​ • 遍历是最基本的运算,是树中所有其他运算的基础.

image-20221206175545467

• 二叉树的三种遍历方式

​ • 先序遍历:

​ 根节点–>左子树–>右子树 : ABDGCEF

​ • 中序遍历:

​ 左子树–>根节点–>右子树 : DGBAECF

​ • 后序遍历:

​ 左子树–>右子树–>根节点 : GDBEFCA

先序遍历的递归算法

▪ 先序遍历二叉树的过程

​ •访问根节点

​ • 先序遍历左子树

​ • 先序遍历右子树

构建思路 :

先遍历根节点 , 然后再遍历其左子树和右子树,这是一个层级,把其左子树或右子树再次当做一个独立的树去调用(每个节点被传入调用的时候,都当了一次根节点,所以才有机会被输出),目的就是输出访问一遍,

代码实现:

//传入要遍历的树的根节点
void PreOrder(BTNode *b)
{
	//先判断传入的根节点是否为空,为空则无操作
    if(b!=NULL)
    {
        //根节点不为空,就先输出根节点
    	printf("%c",b->data);
        //然后输出左子树和右子树
        PreOrder(b->lchild);
        PreOrder(b->rchild);        
    }        
}    

中序和后序遍历的递归算法

● 中序遍历二叉树的过程

​ • 中序遍历左子树

​ • 访问根节点

​ • 中序遍历右子树

思路: 都差不多,都是在同一层级上进行递归调用,我们换一下顺序即可

代码实现:

//传入要遍历的树的根节点
void PreOrder(BTNode *b)
{
	//先判断传入的根节点是否为空,为空则无操作
    if(b!=NULL)
    {
        //先输出左子树
         PreOrder(b->lchild);
        //然后输出根节点
    	printf("%c",b->data);
        //最后输出右子树
        PreOrder(b->rchild);        
    }        
}  

● 后序遍历二叉树的过程

​ • 后序遍历左子树

​ • 后序遍历右子树

​ • 访问根节点

代码实现:

//传入要遍历的树的根节点
void PreOrder(BTNode *b)
{
	//先判断传入的根节点是否为空,为空则无操作
    if(b!=NULL)
    {
        //先输出左子树
        PreOrder(b->lchild);
        //然后输出右子树
        PreOrder(b->rchild); 
		//最后输出根节点
    	printf("%c",b->data);
    }        
}  

二叉树遍历的相关问题

♥问题1

​ • 假设二叉树采用二叉链式存储 ,设计算法,计算一棵给定二叉树的所有节点个数

解题模型

​ •解:计算一棵二叉树b中所有节点个数的递归模型f(b)如下:

image-20221206181905933

▪算法构思:

我们既然要算二叉树有几个节点,不如就把每个节点都访问一遍, 那怎么去访问呢? 当然是一层一层的去访问, 所以我们需要在同一层级上进行规划好,剩下的交给代码调用自身, 去返回每一层的值即可.当我们把一个层级的所有情况处理完, 那当再去调用处理其他层级的子树的时候, 我们就可以游刃有余了.

▪代码实现:

//传入要计算的二叉树的根节点
int Nodes(BTNode *b)
{
    //如果传入的根节点为空,则说明无节点,返回0
	if(b==NULL)
    {
    	return 0;
    }
//否则就说明起码有一个节点, 此时我们需要考虑根节点的左右子树的个数,左右子树节点个数总和加一就是我们所要求的传入的二叉树的节点个数
	else
    {
        //调用左子树和右子树,然后返回其节点个数,其和加一就是二叉树节点个数
    	return (Nodes(b->lchild)+Nodes(b->rchild)+1);
    }
}    

♥问题2

​ • 假设二叉树采用二叉链式存储结构存储,试设计一个算法输出一棵给定二叉树的所有叶子节点

解题模型

♥解:输出一棵二叉树的所有叶子节点的递归模型f()如下

​ • 不做任何事情 若b = NULl

​ • 输出*b节点的data域 若 *b 为叶子节点

​ • f(b->lchild);f(b->rchild) 其他情况

image-20221206192616144

构建思路:

当我们要输出一棵二叉树的时候,我们先采用根左右的方式 , 这样容易处理,

①当传入的根节点为空时候,那就不处理

②当传入的根节点不为空的时候,什么时候输出这个根节点呢?

就是当此根节点就是叶子节点, 就将其输出

③当此根节点还有孩子的时候,说明其不是叶子节点,我们接着往下递归遍历即可

​ (1)把其左子树的叶子节点输出

​ (2)把其右子树的叶子节点输出

代码如下:

//传入树的根节点
void DispLeaf(BTNode *b)
{
	//当其不为空时,接着往下走,看其后面有没有叶子节点
    if(b!=NULL)
    {
    	//如果此根节点没有孩子,说明其就是叶子节点,输出其数据域即可
        if(b->lchild==NULL && b->rchild == NULL)
        {
        	printf("%c,b->data");
        }   
        //不是叶子节点就说明其有孩子,输出其孩子的叶子节点即可
        else
        {
        	DispLeaf(b->lchild);
        	DispLeaf(b->rchild);            
        }
    }      
}  

♥问题3

二叉树(没有值相同的节点)采用二叉链式存储结构,设计一个算法Level(b,x,h),

返回二叉链b中data值为x的节点的层数.

算法构思:

我们既然要遍历二叉树特定节点的层数, 就需要遍历所有节点, 所以我们要定义遍历节点的指针*b,

传入寻找的值, 并且还需要定义一个存储当前对比到的节点的层数h

然后我们采用先序遍历, 先在同一层级进行遍历操作 ,

• 如果传入的根节点为空,则返回0

• 如果传入的根节点就是所找的节点, 就返回此时的层数 h

• 如果上述两种情况都不符合, 就接着看其左右孩子中是否有所找的节点

注意: 我们每次传入子树的时候, 就需要在此层级的层数h基础上加一,表示深度加一,到了下一个层级

代码构建:

//传入要对比的二叉树的根节点的指针,要寻找的节点,此时正在遍历的节点的层数
//注意:此时 *b 里面存储的是正在进行遍历对比的节点
int Level(BTNode *b,ElemType x,int h)
{
    //定义子树的深度
    int I = 0;
	//如果传入的节点为空,就返回0
    if(b==NULL)
    {
    	return 0;
    }        
    //如果传入的节点的不为空,其数据域符合要找的节点就返回其层数
    else if(b->data==x)
    {
		return h;
    }        
    //上两种情况不符合,就判定其有孩子,判断其左右孩子是否存在要找的节点
    else
    {
        //先找其左子树,是否有所要找的节点,然后记录其深度
		I=Level(b->lchild,x,h+1);
        //如果找不到,那每次调用就返回0,接着找右子树
        if(I==0)
        {
            //调用右子树,找到找不到都会返回,无所谓了
        	return Level(b->rchild,x,h+1);
        }
        //不为0就说明找到了
        else
        {
        	return I;
        }                     
    }        
}    
//主函数调用
int main()
{
    //定义构造的二叉树
	BTNode *b;
    //定义层数
    int h;
    //定义要找的特定节点
    ElemType x;
    //构造二叉树
    CreateBTNode(b,"A(B(D(,G)),C(E,F))");
    //输入要找的节点
    scanf("%c",&x);
    //得出调用特定节点的层数
    h = Level(b,x,1);
//    ....
}    

♥问题4

设计一个算法判断两颗二叉树是否相似

算法思路:

​ • 所谓二叉树 t1 和 t2 相似

​ ①t1和t2都是空二叉树,相似;

​ ②t1和t2其中只有一个为空,肯定不相似;

​ ③两个树都不为空,就要对比其子树了—t1的左子树和 t2的左子树是否相似,

​ t1的右子树和 t2的右子树是否相似 .其左子树和右子树都相似我们才能说明两者相似.

解题模型:

解:判断两颗二叉树是否相似的递归模型f()如下:

​ f(t1,t2)=true 若 t1=t2=NULL

​ f(t1,t2)=false 若t1、t2之一为NULL,另一不为NULL

​ f(t1,t2)=f(t1->lchild,t2->lchild)&&f(t1->rchild,t2->rchild) 其他情况

代码构建:

//传入两个二叉树的根节点指针
int Like(BTNode *b1,BTNode *b2)
{
	//定义存储是否相似的标志位
    int like1,like2;
    //如果都是空,则相当于相似
    if(b1==NULL&&b2==NULL)
    {
    	return 1;
    }        
    //否则如果只有一个空,一个不空,则必然不想似
    else if(b1==NULL||b2==NULL)
    {
    	return 0;
    }        
    //否则就说明其有子树,就对比其左子树和右子树
    else
    {
        //调用对比左子树,返回标志位
        like1=Like(b1->lchild,b2->rchild);
        //调用对比右子树,返回标志位
        like2=Like(b1->rchild,b2->rchild);    
        //对比两个子树是否相等,标志位异或运算
        return (like1 && like2);
    }        
}

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

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

相关文章

mysql读写分离

MySQL读写分离 原理 读写分离基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。 读写分离就是只在主服务器上写&…

自学前端到什么程度,可以去找工作呢?

前言 可以看看现在市面上关于前端工程师职业招聘的相关要求,从以下两个的招聘可以看出,无论是普通的前端构造工程师还是高级前端开发工程师,对于h5、css3、es6以及相关框架如vue、react等都需要有深入的认知并能熟练运用 基于上面的相关要求…

刷爆力扣之第三大的数

刷爆力扣之第三大的数 HELLO,各位看官大大好,我是阿呆 🙈🙈🙈 今天阿呆继续记录下力扣刷题过程,收录在专栏算法中 😜😜😜 该专栏按照不同类别标签进行刷题,每…

(四)Spring Security Oauth2.0 源码分析--客户端端鉴权(token校验)

一 引言 在上篇文章我们分析了token的获取过程,那么拿到token后,将token放在请求头中进行资源的访问,客户端是如如何对token进行解析的呢,本文带你走进token校验的源码解析,基本流程如下所示 客户端向资源服务器发起请求时,在请求头Authorization携带申请的token请求被Filte…

网络编程——BIO与NIO介绍与底层原理

BIO BIO(Blocking IO) 又称同步阻塞IO,一个客户端由一个线程来进行处理 当客户端建立连接后,服务端会开辟线程用来与客户端进行连接。以下两种情况会造成IO阻塞: 服务端会一直阻塞,直到和客户端进行连接客户端也会一直阻塞&…

CPP 核心编程9-STL

STL初识 2.1 STL的诞生 长久以来,软件界一直希望建立一种可重复利用的东西C的面向对象和泛型编程思想,目的就是复用性的提升大多情况下,数据结构和算法都未能有一套标准,导致被迫从事大量重复工作为了建立数据结构和算法的一套标准,诞生了S…

四、文件管理(二)目录

目录 2.0文件控制块和索引结点 2.1目录的结构 2.1.1单级目录结构 2.1.2两级目录结构 2.1.3树形目录结构 2.1.4有向无环图目录结构 2.2目录的操作 2.4文件共享 2.4.1基于索引结点(硬链接) 2.4.2基于符号链(软链接) 2.0文…

前端开发是做什么的?工作职责

想要了解前端从业者的工作职责,需要从一个完整网站应用产生流程入手,一个网站应用从无到有的过程大致如下 : 1)产品经理与甲方反复沟通交流,逐步确定产品需求完成设计草图; 2)产品经理根据需求…

如何在centos上安装nvidia docker

当基于nvidia gpu开发的docker镜像在实际部署时,需要先安装nvidia docker。那么如何安装nvidia docker呢。下面将详细介绍下。 安装原生docker yum -y install docker-io 下载nvidia docker安装包 我下载的是rpm文件,具体见截图 安装nvidia docker…

word如何给论文加引用文献

给论文加引用文献其实差不多就是加了个链接,通过点击链接跳转到文末最后展示引用文献额作者,论文名等等信息,给论文加引用文献只要有一下几步: 一、设置参考文献标号字体格式 对于论文中的文献,首先设置论文前序号的…

redis基础6——缓存穿透、缓存击穿、缓存雪崩

文章目录一、缓存穿透(双库为空)1.1 基础概念1.2 解决办法1.2.1 业务层校验1.2.2 设置key过期时间1.2.3 布隆过滤器1.2.3.1 原理1.2.3.1.1 哈希函数使用1.2.3.1.2 布隆过滤器数据结构1.2.3.1.2.1 映射函数执行过程1.2.3.1.2.2 布隆过滤器的误判率1.2.3.2…

华为机试 - 最大化控制资源成本

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 公司创新实验室正在研究如何最小化资源成本,最大化资源利用率,请你设计算法帮他们解决一个任务混部问题: 有taskNum项任务,每个任务有开始时间&#xf…

数字图像处理实验(一)|图像的基本操作和基本统计指标计算

文章目录一、实验目的二、实验主要仪器设备三、实验原理(1)将一幅图像视为一个二维矩阵。(2)利用MATLAB图像处理工具箱读、写和显示图像文件。(3)计算图像的有关统计参数。(4)改变图像尺寸、旋转图像、裁剪图像四、实验内容(1)用imwrite写入图像(2) 用imread读入一幅图像(自选)…

opencv c++ 图像形态学操作

1、图像的形态学操作 包括图像的腐蚀、膨胀、开、闭、形态学梯度、顶帽、黑帽、分支主题、结构元素等操作。 具体概念参考:(41条消息) 图像处理-形态学处理_Gooddz的博客-CSDN博客_图像处理 形态学 1.1、膨胀 用33的核去扫描二值图像,当核与图像中的前景…

[附源码]JAVA毕业设计仟侬堂茶具网站(系统+LW)

[附源码]JAVA毕业设计仟侬堂茶具网站(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术&a…

LeetCode中等题之查找和替换模式

题目 你有一个单词列表 words 和一个模式 pattern,你想知道 words 中的哪些单词与模式匹配。 如果存在字母的排列 p ,使得将模式中的每个字母 x 替换为 p(x) 之后,我们就得到了所需的单词,那么单词与模式是匹配的。 &#xff0…

Git(第二篇)——Git的常见操作

Git(第二篇)——Git的常见操作 目录Git(第二篇)——Git的常见操作一、Git版本控制介绍组成结构图命令速查常用命令二、下载并安装GIT设置字体查询git三、码云上的操作码云配置环境注册账号登录码云创建仓库创建远程仓库(在码云官网…

通讯录管理系统

目录 1.系统需求 2.创建项目 3.菜单功能 4.退出功能 5.添加联系人 5.1设计联系人结构体、设计通讯录结构体 5.2main函数中创建通讯录 5.3封装添加联系人函数 5.4测试添加联系人 6.显示联系人 7.删除联系人 7.1封装检测联系人是否存在 7.2删除联系人,测试删除联…

当我们的执行 java -jar xxx.jar 的时候底层到底做了什么?

大家都知道我们常用的 SpringBoot 项目最终在线上运行的时候都是通过启动 java -jar xxx.jar 命令来运行的。 那你有没有想过一个问题,那就是当我们执行 java -jar 命令后,到底底层做了什么就启动了我们的 SpringBoot 应用呢? 或者说一个 S…

Redux使用详解(一) Redux的核心思想与基本使用

Redux 理解javascript纯函数 函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念; 在react开发中纯函数是被多次提及的; 比如react中组件就被要求像是一个纯函数(为什么…