什么是递归深度

递归深度就是递归函数在内存中,同时存在的最大次数
例如下面这段求阶乘的代码:
Java:

  1. int factorial(int n) {
  2. if (n == 1) {
  3. return 1;
  4. }
  5. return factorial(n - 1) * n;
  6. }

Python:

  1. def factorial(n):
  2. if n == 1:
  3. return 1
  4. return factorial(n-1) * n

C++:

  1. int factorial(int n) {
  2. if (n == 1) {
  3. return 1;
  4. }
  5. return factorial(n - 1) * n;
  6. }

n=100时,递归深度就是100。一般来说,我们更关心递归深度的数量级,在该阶乘函数中递归深度是O(n)O(n)O(n),而在二分查找中,递归深度是O(log(n))O(log(n))O(log(n))。在后面的教程中,我们还会学到基于递归的快速排序、归并排序、以及平衡二叉树的遍历,这些的递归深度都是(O(log(n))(O(log(n))(O(log(n))。注意,此处说的是递归深度,而并非时间复杂度。

太深的递归会内存溢出

首先,函数本身也是在内存中占空间的,主要用于存储传递的参数,以及调用代码的返回地址。
函数的调用,会在内存的栈空间中开辟新空间,来存放子函数。递归函数更是会不断占用栈空间,例如该阶乘函数,展开到最后n=1时,内存中会存在factorial(100), factorial(99), factorial(98) ... factorial(1)这些函数,它们从栈底向栈顶方向不断扩展。
当递归过深时,栈空间会被耗尽,这时就无法开辟新的函数,会报出stack overflow这样的错误。
所以,在考虑空间复杂度时,递归函数的深度也是要考虑进去的

Follow up:
尾递归:若递归函数中,递归调用是整个函数体中最后的语句,且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。(上例factorial函数满足前者,但不满足后者,故不是尾递归函数)
尾递归函数的特点是:在递归展开后该函数不再做任何操作,这意味着该函数可以不等子函数执行完,自己直接销毁,这样就不再占用内存。一个递归深度O(n)O(n)O(n)的尾递归函数,可以做到只占用O(1)O(1)O(1)空间。这极大的优化了栈空间的利用。
但要注意,这种内存优化是由编译器决定是否要采取的,不过大多数现代的编译器会利用这种特点自动生成优化的代码。在实际工作当中,尽量写尾递归函数,是很好的习惯。
而在算法题当中,计算空间复杂度时,建议还是老老实实地算空间复杂度了,尾递归这种优化提一下也是可以,但别太在意。

尾递归 递归函数中,递归调用是整个函数体中最后的语句,且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归,空间复杂度是O(1)的更多相关文章

  1. VC/MFC中通过CWebPage类调用javascript函数(给js函数传参,并取得返回值)

    转自:http://www.cnblogs.com/javaexam2/archive/2012/07/14/2632959.html ①需要一个别人写好的类CWebPage,将其对于的两个文件Web ...

  2. VC与JavaScript交互(三) --- CWebPage类调用javascript函数(给js函数传参,并取得返回值)

    ①需要一个别人写好的类CWebPage,将其对于的两个文件WebPage.h和WebPage.cpp添加到工程中. ②添加WebBrowser控件,在视图/对话框类的头文件中#include &quo ...

  3. jQuery find() 搜索所有段落中的后代 C# find() 第一个匹配元素 Func 有返回值 Action是没有返回值 Predicate 只有一个参数且返回值为bool 表达式树Expression

    所有p后代span Id为 TotalProject 的 select 标签 的后代 option标签 为选中的 text using System; using System.Collections ...

  4. 调用个别f5 负载端口为80的vs时,返回值为空的问题

    现状: vs负载端口为80并添加XFF,pool包含2个member,member的monitor端口为80&9000. 故障现象: 应用同事描述说再完全复制了一个member并添加到pool ...

  5. EF5中 执行 sql语句使用Database.ExecuteSqlCommand 返回影响的行数 ; EF5执行sql查询语句 Database.SqlQuery 带返回值

    一: 执行sql语句,返回受影响的行数 在mysql里面,如果没有影响,那么返回行数为  -1 ,sqlserver 里面  还没有测试过 using (var ctx = new MyDbConte ...

  6. stl中的transform()注意其与for_each的不同点(有无返回值)

    #include<iostream> using namespace std; #include"vector" #include"algorithm&quo ...

  7. JS中函数的本质,定义、调用,以及函数的参数和返回值

    要用面向对象的方式去编程,而不要用面向过程的方式去编程 对象是各种类型的数据的集合,可以是数字.字符串.数组.函数.对象…… 对象中的内容以键值对方式进行存储 对象要赋值给一个变量 var cat={ ...

  8. .NET中如何在同步代码块中调用异步方法

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 在同步代码块中调用异步方法,方法有很多. 一.对于有返回值的Task 在同步代码块中直接访问 Task 的 Result ...

  9. shell调用函数返回值深入分析

    编写shell脚本过程中,我们经常会自定义一些函数,并根据函数的返回值不同来执行相应的流程,那么我们如何来获取函数的返回值呢? 首先shell中调用函数有两种方式: 第一种:value=`functi ...

随机推荐

  1. FreeSql 访问 Oracle 解决大小写问题

    方法一 new FreeSqlBuilder() .UseSyncStructureToUpper(true) .Build() 方法二 全局转换实体属性名方法,这种只能转属性. 其实是通过Aop方法 ...

  2. Python UDP小程序

    为了做UDP的测试,采用了nc和Python的服务器端. nc的安装和使用: yum install -y nc nc -vuz Python的UDP服务器端小程序: # -*- coding: UT ...

  3. AI保存文件出现了未知错误 (Adobe Illustrator)

    可能的原因如下:1 把文件中所有的文字全选,转成曲线,把所有的文字都创建成轮廓2 新建一个页面,把制作的复制到新页面里3 需要把图层全部解锁再保存4 没有权限,设置一下即可5 PRINT SPOOLE ...

  4. Orm 配置说明

    一.在线技术文档: http://files.cnblogs.com/files/humble/d.pdf   二.使用的大致流程   1.首先下载代码生成器,可以一键生成项目Model层;(其中含有 ...

  5. QML学习(五)——<TextInput和TextEdif输入框>

    这一篇来看两个用于文本输入的项目,分别是作为单行文本输入的 TextInput 和多行文本输入的 TextEdit . 下面开始教程. TextInput TextInput 项目用来显示单行可编辑的 ...

  6. cad 一个小技巧--复制视口带冻结信息

    cad使用 ctrl+c 和 ctrl+v 进行跨文件复制视口的时候,会出现复制视口冻结信息丢失,因为你只选择了视口进行复制, 如果要实现带上冻结信息,那么要把含有相关图层的图元一起 ctrl+c/v ...

  7. 自定义标签&JSON数据处理

    最近几日去参加一些面试,多多少少有一些收获. 现将遇到的一些面试题,做一下分析和总结. 1.使用原生JS,不能使用递归,查找dom中所有以“<com-”开头的自定义标签tagName. < ...

  8. [转帖]Java Netty简介

    Java Netty简介 https://www.cnblogs.com/ghj1976/p/3779820.html Posted on 2014-06-10 13:41 蝈蝈俊 阅读(2992) ...

  9. 使用scrapy框架做武林中文网的爬虫

    一.安装 首先scrapy的安装之前需要安装这个模块:wheel.lxml.Twisted.pywin32,最后在安装scrapy pip install wheel pip install lxml ...

  10. Linux平台上常用到的c语言开发程序

    Linux操作系统上大部分应用程序都是基于C语言开发的.小编将简单介绍Linux平台上常用的C语言开发程序. 一.C程序的结构1.函数 必须有一个且只能有一个主函数main(),主函数的名为main. ...