递归函数引用参数对工作栈大小影响的分析
来源:互联网 发布:爱国者hd816软件下载 编辑:程序博客网 时间:2024/06/06 02:58
本文从递归函数参数的角度来分析,递归函数调用时递归工作栈中工作记录减肥的可能性。
用最简单的求阶层函数来举例:
n! = n*(n-1)*(n-2)***2*1
常见的递归实现如下:
int fun(int n)
{
if( n<=1 ) return 1;
return n*fun(n-1);
}
不用多说,这个实现下每次递归调用都会在当前层的工作记录中分配一个4字节(IBM兼容机)的空间来存放n的值。若栈的深度为DEPTH,那么一共需要DEPTH×4个字节存放参数。
那么能不能避免这些存储空间呢,我们来看看引用的情况:
int fun(int &n)
{
if( n<=1 ) return 1;
return n*fun(n-1);
}
这段代码编译不能通过,原因是n-1只是一个右值。这里简单介绍一下c++中的无名对象(变量)。c++中的无名对象与const常量有些相似,他们都只能做右值而不能做左值,区别是const常量是有地址的可以取地址,而无名对象一般是不可以的。这里n-1有点无名对象的味道,因为fun要求一个变量引用。由于n-1是右值,所以把参数类型改成int fun(const int & n)就可以了。
int fun(const int &n)
{
if( n<=1 ) return 1;
return n*fun(n-1);
}
现在运行通过了,但是栈空间需求仍然没有减少,因为引用的是无名对象,无名对象只是寄存器中的一个值,是没有RAM地址的。所以每递归调用一次,就会在工作记录中分配空间来存放n-1,实际效果相当于const int n = n-1;
那么换个思路。以上程序之所以如此是因为传给递归函数的不是n本身,现设计如下:
int fun(const int & n)
{
cout<<(long)&n<<endl;
if( n<=1 ) return 1;
--n;
return (n+1)*fun(n);
}
这个程序运行正确而且所有的n确实是最外面的那个n的引用(打印的地址均一致)。有些人会怀疑这个程序不能正确的求出n!。想想也对,当递归不断深入到最里层的时候n=1,递归回退的时候n仍然还是1,那结果不就成了1×2×2×2××××2了么??您可以试试看,结果可能出乎您的预料:计算出的确实是 n! 原因如下:
每调用一层时先计算n+1,n+1的结果保存在register中,进入下一层递归前编译器会把适当的register的值压栈以便日后恢复,这里某个寄存器就存放着运算的中间结果n+1。日后返回该层时虽然此时n确实是1,但是n+1的结果已经计算过,所以只是从栈顶取出n+1而非重新计算。作为思考,您可以试试看将(n+1)*fun(n)改成fun(n)*(n+1),它将得出错误的结果。
看来,递归调用函数使用引用参数和普通使用引用参数的非递归调用函数是有区别的:并不是使用了引用参数后就一定能够节省栈的空间,这取决于具体的递归函数(复杂。。。^_^)
当然,在递归函数中使用引用参数还有一种目的,当然是为了改变实参的数值罗。对于非内部类型的对象而言,使用引用往往可以既节省空间又同时可以修改实参的值,这里就不再举例了。
- 递归函数引用参数对工作栈大小影响的分析
- 不同的参数传递方式对递归函数递归深度的影响
- 函数参数按引用传递和按值传递对动态联编的影响
- gcc -g参数对程序大小的影响
- Thrift框架中函数栈的大小对程序的影响
- 生活对工作的影响
- ASP中函数调用对参数的影响
- ASP中函数调用对参数的影响
- C++的引用-01引用作函数参数分析
- 函数指针使用与直接函数调用对程序代码大小的影响
- 通过Android源码分析LinearLayout的layout_weight与weightsum对布局大小的影响
- 分析Android studio3.0的instant run开启关闭对APK大小的影响
- 方法递归对性能的影响
- [笔记]对有引用参数的函数的调用
- 虚函数&虚继承存在对类的大小的影响
- 继承、 虚继承和虚函数表对类的大小的影响
- 判断一个函数里对参数的修改是否对外部产生影响
- cpu的工作模式对功耗影响
- Google 2013 campus recruitment
- 判断文件结束函数(feof)
- Eclipse 常用快捷键
- Execl中vlookup函数的使用实例
- 浅谈资源收集器GC
- 递归函数引用参数对工作栈大小影响的分析
- 代理模式(Proxy Pattern)(三):HeadFirst使用java API创建一个保护代理
- linux下发邮件mail
- Repeater结合linkbutton实现分页
- IOS学习:常用第三方库(ASIHttpRequest)
- 硬盘知识及其结构
- Android SDK下边tools和platform-tools的区别
- 元件为基础的设计
- 十进制输出AX中的内容