尾调用和尾递归--学习笔记

尾调用

尾调用是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。这种情形下称该调用位置为尾位置。若这个函数在尾位置调用本身(或是一个尾调用本身的其他函数等等),则称这种情况为尾递归,是递归的一种特殊情形。尾调用不一定是递归调用,但是尾递归特别有用,也比较容易实现。

在程序运行时,计算机会为应用程序分配一定的内存空间;应用程序则会自行分配所获得的内存空间,其中一部分被用于记录程序中正在调用的各个函数的运行情况,这就是函数的调用栈。常规的函数调用总是会在调用栈最上层添加一个新的堆栈帧(stack frame,也翻译为“栈帧”或简称为“帧”),这个过程被称作“入栈”或“压栈”(意即把新的帧压在栈顶)。当函数的调用层数非常多时,调用栈会消耗不少内存,甚至会撑爆内存空间(栈溢出),造成程序严重卡顿或意外崩溃。尾调用的调用栈则特别易于优化,从而可减少内存空间的使用,也能提高运行速度。其中,对尾递归情形的优化效果最为明显,尤其是递归算法非常复杂的情形。

一般来说,尾调用消除是可选的,可以用,也可以不用。然而,在函数编程语言中,语言标准通常会要求编译器或运行平台实现尾调用消除。这让程序员可以用递归取代循环而不丧失性能。

尾调用优化

我们知道,函数调用的时候在内存会生成一条调用记录,我们称它为调用桢 (call frame),保存着函数地址和局部变量等信息。如果函数 A 的内部调用了函数 B,那么在调用记录 A 的上方会 PUSH 调用记录 B,当函数 B 执行完成后会 POP 调用记录 B,这听起来其实就是一个调用栈 (call stack)
在这里插入图片描述
尾调用由于是函数的最后一步操作,所以不需要在继续保留当前函数地址和变量等信息,它的调用桢可以被下一个调用函数复用,这就是尾调用优化 (Tail Call Optimization,TCO)

在这里插入图片描述

尾递归

若函数在尾位置调用自身(或是一个尾调用本身的其他函数等等),则称这种情况为尾递归。尾递归也是递归的一种特殊情形。尾递归是一种特殊的尾调用,即在尾部直接调用自身的递归函数。对尾递归的优化也是关注尾调用的主要原因。尾调用不一定是递归调用,但是尾递归特别有用,也比较容易实现。

尾递归在普通尾调用的基础上,多出了2个特征:

  1. 在尾部调用的是函数自身 (Self-called);

  2. 可通过优化,使得计算仅占用常量栈空间 (Stack Space)。

参考资料:
作者:哈希说
原文链接:https://xie.infoq.cn/article/5fb06b11a5d4b15631eaa2153

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值