“递归”的实现 及 与“非递归”的效率比较
(2008-07-27 19:02:17)
标签:
递归非递归栈 |
分类: 数据结构 |
一、递归函数的实现:
递归函数由操作系统的“系统栈”来实现,在调用另一函数前,操作系统先要:
1、下一条语句的地址入栈,即返回地址入栈:
2、被调用函数的形式参数 入栈,
3、被调用函数的局部变量 入栈
当本次函数调用结束后:
1、保存函数返回值 (至通用寄存器EAX中)。
2、清理堆栈:先将局部变量出栈,再将形式参数出栈。至于由调用函数或被调用函数执行,参见调用约定
3、依据保存的返回地址将控制转移到调用函数。
关键字 |
清理堆栈 |
参数入栈顺序 |
函数名称修饰(C) |
__cdecl |
调用函数 |
右 à 左 |
_函数名 |
__stdcall |
被调用函数 |
右 à 左 |
_函数名@数字 |
__fastcall |
被调用函数 |
右 à 左 |
@函数名@数字 |
thiscall(非关键字) |
被调用函数 |
右 à 左 |
/ |
二、递归的“非递归化”及效率比较
1、用“自定义栈”来实现非递归化
在时间效率上:
“自定义栈”如果是“手动实现”,即"malloc(); stack[p++]=n;",省去了返回地址和局部变量出入栈问题,效率会高点;
但如果使用标准的stack类(包括模板类的实例),在调用“pop、push”时同样会调用系统栈,即涉及返回地址的出入栈问题。这时只有当递归函数中局部变量很多时效率才会高点,因“自定义栈”不需要存储被调用函数的局部变量。
至于递归函数内调用其它函数的多少是无影响的,因为其它函数在开始递归前已结束或未调用。
至于消除无效递归,那是程序设计的问题。使用“自定义栈”时可以消除的无效出入栈,在递归中就变成了除无效递归问题。
另外说点“栈存储结构“问题,栈一般是使用“顺序栈”而非“链式栈”,因为栈不涉及特定元素的插入、删除操作。而如果使用“链式栈”,在压入和弹出元素时,将会涉及malloc内存分配的问题,效率就大大降低。