c++(递归和堆栈)
看过我前面博客的朋友都清楚,函数调用主要依靠ebp和esp的堆栈互动来实现的。那么递归呢,最主要的特色就是函数自己调用自己。如果一个函数调用的是自己本身,那么这个函数就是递归函数。
我们可以看一下普通函数的调用怎么样的。试想如果函数A调用了函数B,函数B又调用了函数C,那么在堆栈中的数据是怎么保存的呢?
函数A ^
函数B | (地址递减)
函数C |
如果是递归函数呢,举一个简单的递归函数为例:
int iterate(int value)
{
if(value == 1)
return 1;
return value + iterate(value -1);
}
下面我们使用一个函数进行调用,看看会发生什么情况?
void process()
{
int value = iterate(6);
}
看看此时内存堆栈是什么样的?
iterate(int 1) line 96
iterate(int 2) line 97 + 12 bytes
iterate(int 3) line 97 + 12 bytes
iterate(int 4) line 97 + 12 bytes
iterate(int 5) line 97 + 12 bytes
iterate(int 6) line 97 + 12 bytes
process() line 102 + 7 bytes
main() line 108
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817067()
大家也看到了上面的代码,递归函数和普通的函数也没有什么差别。除了自己调用本身之外,他就是一个普通的函数。那么这个函数递归到什么时候返回呢?这就是递归函数的关键了。我们看到iterate函数到1就停止了,所以上面的堆栈在(value == 1)即return。所以一个递归函数最关键的部分就是两点:(1)递归策略;(2)函数出口。
看到这里,大家可能感到递归函数不过如此,事实上也是这样。但是,还有一点大家需要牢记在心,递归的深度是我们必须考虑的一个问题。只有递归深度在一个可控的范围内,那么整个递归过程都是可控的。那什么时候不可控呢?那就是递归深度超过了一定的数字?这个数字和具体的线程堆栈长度有关?等到堆栈溢出了,那么获得的数据已经失去了真实性,所以也就没有意义了。
我们把上面的问题推广一下,如何用自己定义的堆栈模拟上面的递归调用呢?这样既能满足递归的属性,又能确保函数深度可控。
大家可以先写一下自己的方案,下面只是我个人的一个思路。
int iterate(int value)
{
int count = 0;
int number =0; push(value);
while(-1 != (number = pop()))
{
if(1 != number)
push(number -1);
count += number;
} return count;
}
c++(递归和堆栈)的更多相关文章
- 翻译连载 | 第 9 章:递归(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- c++2(循环和递归)
其实编程的朋友知道,不管学什么语言,循环和递归是两个必须学习的内容.当然,如果循环还好理解一点,那么递归却没有那么简单.我们曾经对递归讳莫如深,但是我想告诉大家的是,递归其实没有那么可怕.所谓的递归就 ...
- PAT复杂度_最大子列和问题、最大子列和变种
01-复杂度1. 最大子列和问题 给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j ...
- LTE Manual ——Logging(翻译)
LTE Manual ——Logging(翻译) (本文为个人学习笔记,如有不当的地方,欢迎指正!) 9 Logging ns-3 日志功能可以用于监测或调试仿真程序的进展.日志输出可以通过 ma ...
- 走进AngularJs(三)自定义指令-----(上)
一.有感而发的一些话 在学习ng之前有听前辈说过,angular上手比较难,初学者可能不太适应其语法以及思想.随着对ng探索的一步步深入,也确实感觉到了这一点,尤其是框架内部的某些执行机制,其复杂程度 ...
- angularjs学习总结 详细教程(转载)
1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...
- Tree
//Header.h #ifndef _HEAD_ #define _HEAD_ #include <queue> #include <iostream> using name ...
- stack overflow错误分析
stack overflow(堆栈溢出)就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了老的堆栈数据. 或者解释为 在长字符串中嵌入一段代码,并将过程的返回地址 ...
- 淘宝SKU组合查询算法实现
淘宝SKU组合查询算法实现 2015-11-14 16:18 1140人阅读 评论(0) 收藏 举报 分类: JavaScript(14) 目录(?)[+] 前端有多少事情可以做,能做到多 ...
随机推荐
- tee 命令详解
作用:将数据重定向到文件,另一方面还可以提供一份重定向数据的副本作为后续命令的stdin . 简单的说就是把数据重定向给文件和屏幕上. 注意:存在缓存机制,每1024 字节输出一次, 若从管道接受数据 ...
- lesson - 3 ls /cd /path /alias /快捷键
内容概要: 1. 命令ls -l 详细信息-a 查看隐藏的文件或目录-d 只看目录本身,不列出目录下面的文件和目录-t 以时间先后排序 2 目录结构/bin, /sbin, /usr/bi ...
- git stash的用法
使用git stash git stash的使用场景是这样的: 当你正在你的分支下进行开发时,这时候你可能需要切换到你的另一个分支去,你可能要pull新的代码下来,但是你又不想添加无用的commit. ...
- 缓存(Cache)
l如果每次进入页面的时候都查询数据库生成页面内容的话,如果访问量非常大,则网站性能会非常差.而如果只有第一次访问的时候才查询数据库生成页面内容,以后都直接输出内容,则能提高系统性能.这样无论有多少人访 ...
- java接入创蓝253短信验证码
说明 项目是springboot框架 1.短信配置文件 包含验证码发送路径.用户名.密码 chuanglan.requesturl= chuanglan.account= chuanglan.pswd ...
- 三十天学不会TCP,UDP/IP网络编程-TraceRoute的哲学
新年快乐,继续来部分粘贴复制我的这一系列文章啦,如果对和程序员有关的计算机网络知识,和对计算机网络方面的编程有兴趣,欢迎去gitbook(https://www.gitbook.com/@rogerz ...
- 深入.NET数据类型(1)
一.值类型和引用类型 所有的值类型和引用类型的引用都存在"栈"中 1.值类型 命名空间:System.ValueType 值类型数据储存所在的内存区域成为栈 值类型主要包括基本数据 ...
- jQuery实现表的编辑删除添加(增删改查)🌚
代码 : (用到了bootstrap里面的全局css样式和组件,毕竟一把梭.
- Head First设计模式之策略模式
这是学习的第一个设计模式,而书中写的实例相对比较复杂,参考了网上的文章进行总结 一.定义 策略模式(strategy pattern): 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模 ...
- SpringMVC @SessionAttributes注解
@SessionAttributes 注解只能作用到类上 @SessionAttributes(value={"user"},types={String.class}) @Sess ...