调用子程序的含义
在过程和函数的学习中我们知道调用子程序的一般形式是主程序调用子程序A子程序A调用子程序B如图如示这个过程实际上是
@当主程序执行到调用子程序A语句时系统保存一些必要的现场数据然后执行类似于BASIC语言的GOTO语句跳转到子程序A(为了说得简单些我这里忽略了参数传递这个过程)
@当子程序A执行到调用子程序B语句时系统作法如上跳转到子程序B
@子程序B执行完所有语句后跳转回子程序A调用子程序B语句的下一条语句(我这又忽略了返回值处理)
@子程序A执行完后跳转回主程序调用子程序A语句的下一条语句
@主程序执行到结束
做个比较我在吃饭(执行主程序)吃到一半时某人叫我(执行子程序A)话正说到一半电话又响了起来(执行子程序B)我只要先接完电话再和某人把话说完最后把饭吃完(我这饭吃得也够累的了J)
认识递归函数
我们在高中时都学过数学归纳法例
求 n!
我们可以把n!这么定义
也就是说要求!我们必须先求出!要求!必须先求!要求!就必须先求!而!=所以!=!*=再进而求!!分别用函数表示则如图
我们可以观察到除计算!子程序外其他的子程序基本相似我们可以设计这么一个子程序
int factorial(int i){
int res;
res=factorial(I)*i;
return res;
}
那么当执行主程序语句s=factorial()时就会执行factorial()但在执行factorial()又会调用factorial()这时大家要注意factorial()和factorial()虽然是同一个代码段但在内存中它的数据区是两份!而执行factorial()时又会调用factorial()执行factorial()时又会调用factorial()每调用一次factorial函数它就会在内存中新增一个数据区那么这些复制了多份的函数大家可以把它看成是多个不同名的函数来理解;
但我们这个函数有点问题在执行factorial()时它又会调用factorial()造成死循环也就是说在factorial函数中我们要在适当的时候保证不再调用该函数也就是不执行res=factorial(I)*i;这条调用语句所以函数要改成
int factorial(int i){
int res;
if (I>) res=factorial(I)*i; else res=;
return res;
}
那么求!的实际执行过程如图所示
如何考虑用递归的方法来解决问题
例求s=++++++……+n
本来这个问题我们过去常用循环累加的方法而这里如要用递归的方法必须考虑两点
) 能否把问题转化成递归形式的描述;
) 是否有递归结束的边界条件
设:函数s(n)=+++…+(n)+n
显然递归的两个条件都有了
) s(n) =s(n)+n
) s()=
所以源程序为
int progression(int n){
int res;
if (n= )res= else res=progression(n)+n;
return res;
}
递归的应用
中序遍历二叉树
void inorder (BinTree T){
if (T){
inorder(T>lchild);
printf(%cT>data);
inorder(T>rchild);
}
}
现假设树如图(为了讲解方便树很简单)
@执行第一次调用inorderT指向顶结点T不为空所以第二次调用inorder;
@T指向顶结点的左子树结点也就是B不为空所以第三次调用inorder;
@T指向B结点的左子树结点为空所以什么都不执行返回inorder;
@打印B结点的DATA域值b;
@第四次调用inorder去访问B子树的右结点
@T指向B结点的右子树结点为空所以什么都不执行返回inorder;
@返回inorder;
@打印A结点的DATA域值a;
@第五次调用inorder去访问A子树的右结点;
@T指向A结点的右子树结点为空所以什么都不执行返回inorder;
@inorder执行完毕返回