了解递归:普通函数递归和非递归栈式实现之间的区别
时间:2022-07-25
本文章向大家介绍了解递归:普通函数递归和非递归栈式实现之间的区别,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
相关链接 : 递归和栈的关系
以树的遍历为例
先序遍历:
伪代码
void preView(Node node){
print(node.value); // 1
if(node.left != null){
preView(node.left); // 2
}
if(node.right != null){
preView(node.right); // 3
}
}
如果我们用函数栈帧的思想,每调用一个函数,就把一个栈帧入栈
这里的问题就是:栈帧无法为我们提供足够的信息,让我们正确的继续用栈执行递归。
如果编译器编译上述的伪代码,那么在函数栈帧中会保存要返回的地址。在上述情景中,节点2的栈帧中不应该只保存节点2,应该还要保存2执行到第几行了。
继续下去是要执行第二行还是执行第三行(返回的地址)。但是软件实现一般不这么做,也不能这么做,因为我们用纯代码不用嵌入汇编的话,
很难做到像用ret这样的指令一样改变IP寄存器
可以选择在栈帧中保存一个标志,来标识要向左走(递归调用左子节点,代码中行2)还是向右(递归调用右子节点,代码中行3)走,还是说都走过了,要弹出(即已经执行了代码中行2,行3,函数执行完毕返回)。比如一个int变量,如果左子节点已入栈,但右子未入栈,就标记为1。0表示均未递归调用左右子节点,2表示都调用过。
递归子函数的栈帧弹出后,返回到针对当前节点的栈帧:有以下情况
0,如果这个int变量为0,则左右子节点都未被递归调用
1,如果这个int变量为1,则把右子节点对应栈帧入栈,并且把当前栈帧中这个int变量修改成2
2,如果这个int变量为2,则直接把当前栈帧弹出
于是当2的节点对应栈帧出栈后,5的节点对应的栈帧就有了方向,知道要把右子包成一个栈帧入栈
其实在知道左子节点入栈了,但右子节点未入栈后,没必要保存当前栈帧,因为上述伪代码对右子节点的递归是尾递归,即当前函数递归调用当前函数,但是并不期待这个递归调用
给当前的函数带来些什么,递归调用也用不到当前函数栈帧。所以可以直接弹出。
上图可简化:
- Python中的__init__()方法整理中(两种解释)
- 如何找到最优学习率?
- 简单易学的机器学习算法——Rosenblatt感知机
- 多级复制的数据不同步问题(r7笔记第11天)
- 简单易学的机器学习算法——Logistic回归
- Python 用OPEN读文件报错 ,路径以及r
- Oracle 12c PDB浅析(r9笔记第10天)
- merge语句导致的CPU使用率过高的优化(二) (r7笔记第9天)
- 网页爬虫-R语言实现基本函数
- Python中的random模块用于生成随机数
- 简单易学的机器学习算法——极限学习机(ELM)
- 图片数据集太少?Keras Image Data Augmentation 各参数详解
- 备库归档删除策略失效的问题分析 (r7笔记第6天)
- 优化算法——梯度下降法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 离线安装Superset 0.37(截图详细版)
- 如何高速转储、索引和第7层网络流量过滤?
- 爬虫 | JS逆向某验滑动加密(二)
- 闲聊 Kotlin-Native (0) - 我们为什么应该关注一下 Kotlin Native?
- 哈佛大学单细胞课程|笔记汇总 (五)
- 通过源码理解IGMP v1的实现(基于linux1.2.13)
- 微服务下数据一致性的几种实现方式
- 关于mac electron设备权限申请的方法
- 两种实现方式 | 如何查看消费者组的消费情况
- 一致性hash算法(golang)
- 微服务安全吗?
- 掌握Rabbitmq几个重要概念,从一条消息说起
- 超赞!墙裂推荐一个 MySQL 自动化运维工具!
- 设计模式-责任链模式
- 问题 linux下执行.sh 文件出现 no such file or directoryile