从理解js双重递归执行顺序到用递归方式实现二叉树中序遍历

今天在学习力扣上94题二叉树的中序遍历时,js的实现方法之一是递归,但是函数内递归是双重,花了一些时间来理解双重递归调用的执行顺序。
先看如下例子,参考文章(双递归的执行过程理解)
示例代码如下:

	const fn = (n) => {if (n > 0) {console.log('n1====', n)fn(n - 1)console.log('n2====', n)fn(n - 2)console.log('n3====', n)}}fn(3)

我们可以先考虑一下输出的结果是什么呢?
答案揭晓如下:

// n1==== 3
// n1==== 2
// n1==== 1
// n2==== 1
// n3==== 1
// n2==== 2
// n3==== 2
// n2==== 3
// n1==== 1
// n2==== 1
// n3==== 1
// n3==== 3

一开始看到这个结果,真是两眼一黑,什么鬼!那我们先不急,一步步来分析~
1、首先注意第一次递归调用:首次调用时,n=3,所以输出结果n1 = 3是毫无疑问的,接着执行fn(n - 1),因为n - 1 = 2 > 0,所以执行第一次递归没问题吧

2、接着就是一个知识点:进栈
众所周知,js是单线程,fn函数内均为同步执行,所以第一次递归之后,n=3进栈,执行fn(n - 1)的n=2操作,而我把fn(n - 1)执行的过程称为进栈(压栈)。如下图:
在这里插入图片描述
3是最先进栈,所以在栈底。
注意:此时fn(n - 1)以下的代码片段全部未执行。
输出结果为:

n1==== 3
n1==== 2
n1==== 1

当n = 1时,执行fn(n - 1),则n = 0,即if (n > 0)失效。当前递归结束,开始释放栈内存(出栈),而栈是后进先出结构,如下图:
在这里插入图片描述

3、接上图,n=1 出栈,同步执行以下代码片段

	console.log('n2====', n)fn(n - 2)console.log('n3====', n)

所以第四行打印出 n2==== 1
接着执行fn(n - 2),因当前n=1,不符合表达式n>0情况,所以本次递归调用不执行。
接着输出打印 n3==== 1,此时到输出的打印结果第五行。

4、n=1 出栈后,2出栈:
重复上一步,输出:

n2==== 2
n3==== 2

此时到打印结果第7行。

5、n=2 出栈后,3出栈:
输出结果n2==== 3
执行递归fn(n - 2),此时 if 表达式 n = 1 > 0 成立,则从头执行。

注意:此时n = 3进栈,最后一行代码console.log('n3====', n)不执行

执行fn(3 - 2)后:
首先输出n1==== 1,再执行fn(n - 1),表达式不成立,接着向下执行,
输出n2==== 1,向下执行fn(n - 2),表达式不成立,准备出栈,继续向下执行,
输出n3==== 1
最后!注意:之前执行fn(n - 2)时有n = 3进栈!所以此时同步流程结束,需要出栈:
输出最后一个结果n3==== 3
至此,双递归调用流程结束。

// =================================

到这,终于明白双递归是怎么被调用执行的了!~
接下来,我们来看怎么用递归的方式实现二叉树中序遍历:
中序遍历返回顺序是左 => 根/中 => 右,如下图:
在这里插入图片描述
按照中序遍历输出的结果应该是 [4, 2, 5, 1, 6, 3, 7]。

依照上面例子给我们的经验,要获取左子树的最后一个左节点的值再进行操作,那我们可以进行压栈,当左子树的某个左节点left为null时,代表当前节点为最后节点,数据结构大致如下:

const tree = {val: '1',left: {val: '2',left: { val: '4', left: null, right: null },right: { val: '5', left: null, right: null }},right: {val: '3',left: { val: '6', left: null, right: null },right: { val: '7', left: null, right: null }},
}

代码实现如下:

var inorderTraversal = function (root) {let arr = []const fn = (tree) => {if (!tree) returnfn(tree.left)arr.push(tree.val)fn(tree.right)}fn(root)return arr
};console.log(inorderTraversal(tree))

如上,执行fn(tree.left)时,一直在压栈,一直到 { val: '4', left: null, right: null },这一层,执行结束,释放栈,此时栈如下(看val值):
在这里插入图片描述
4首先出栈,执行arr.push(tree.val)后,执行递归fn(tree.right),val=4的这一层,right = null,被return,本次执行结束。
2再次出栈,再执行递归fn(tree.right),成立,arr此时为[4, 2, 5].
1出栈,执行后,arr = [4, 2, 5, 1],
再遍历右子树,以此类推。
中序遍历完成。

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

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

相关文章

微服务保护-流量控制

流量控制 雪崩问题虽然有四种方案,但是限流是避免服务因突发的流量而发生故障,是对微服务雪崩问题的预防。我们先学习这种模式 簇点链路 当请求进入微服务时,首先会访问DispatcherServlet,然后进入Controller、Service、Mapper&…

离线版IP归属地查询

这里简单介绍一下Ip2regionSearcher是什么? ip2region 是准确率 99.9% 的 IP 地址定位库,0.0x毫秒级查询,提供了 Java、PHP、C、Python、Node.js、Golang、C#、Rust、Lua的查询绑定和 Binary、B树、内存三种查询算法! Setp1&…

星际争霸之小霸王之小蜜蜂(十三)--接着奏乐接着舞

系列文章目录 星际争霸之小霸王之小蜜蜂(十二)--猫有九条命 星际争霸之小霸王之小蜜蜂(十一)--杀杀杀 星际争霸之小霸王之小蜜蜂(十)--鼠道 星际争霸之小霸王之小蜜蜂(九)--狂鼠之…

小米华为,化干戈为玉帛!

近日来,手机圈又掀起了各大厂家推出新品的高潮。首先是华为Mate60的推出,其自研的麒麟9000S芯片瞬间点燃了国内手机市场,得到了国内甚至国外业界人士的认可和好评。 而近日网上盛传的小米创始人雷军的“愿意加入华为技术生态圈”的邀请&…

Spring Boot集成Redis实现数据缓存

🌿欢迎来到衍生星球的CSDN博文🌿 🍁本文主要学习Spring Boot集成Redis实现数据缓存 🍁 🌱我是衍生星球,一个从事集成开发的打工人🌱 ⭐️喜欢的朋友可以关注一下🫰🫰&…

SpringMVC-----JSR303以及拦截器

目录 JSR303 什么是JSR303 JSR303的作用 JSR303常用注解 入门使用 拦截器是什么 拦截器的工作原理 拦截器的作用 拦截器的使用 JSR303 什么是JSR303 JSR303是Java为Bean数据合法性校验提供给的标准框架,已经包含在JavaEE6.0中1。 JSR303通过在Bean属性中标…

PostgreSQL 数据类型

文章目录 PostgreSQL数据类型说明PostgreSQL数据类型使用单引号和双引号数据类型转换布尔类型数值类型整型浮点型序列数值的常见操作 字符串类型日期类型枚举类型IP类型JSON&JSONB类型复合类型数组类型 PostgreSQL数据类型说明 PGSQL支持的类型特别丰富,大多数…

爬虫框架Scrapy学习笔记-1

前言 在现代互联网时代,网页数据获取和处理已经成为了重要的技能之一。无论是为了获取信息、做市场研究,还是进行数据分析,掌握网页爬取和数据处理技术都是非常有用的。本文将介绍从网页加载到数据存储的完整过程,包括网络请求、…

python 异常

1.捕获异常 2.密码爆破 3.

【业务功能118】微服务-springcloud-springboot-Kubernetes集群-k8s集群-KubeSphere-OpenELB部署及应用

OpenELB部署及应用 一、OpenELB介绍 网址: openelb.io OpenELB 是一个开源的云原生负载均衡器实现,可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。OpenELB 项目最初由 KubeSphere 社区发…

系统IO和标准IO

一.系统IO 系统 I/O(Input/Output)是计算机操作系统提供给应用程序的一种输入和输出方式。它通过系统调用(系统内核提供的函数)来实现数据的读取和写入。系统 I/O 可以用于与文件、设备(例如磁盘驱动器、网络接口、串…

【1++的C++进阶】之智能指针

👍作者主页:进击的1 🤩 专栏链接:【1的C进阶】 文章目录 一,什么是智能指针二,为什么需要智能指针三,智能指针的发展 一,什么是智能指针 要了解智能指针,我们先要了解RA…