数据结构的魔法,递归调用
一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,叫做递归函数。——《数据结构》严蔚敏
- 两年前在学习C语言的时候,老师就有讲过关于递归调用的问题。当时编程思想较弱的我,在接触了八皇后,汉诺塔之后,也没有对递归调用有很深刻的印象。直到最近,在系统地复习了严奶奶的《数据结构》之后。我对递归调用有了更加深刻的认识。因获得知识而兴奋不已的我也决定写一篇博客来向其他的学习者分享一下我对于递归调用的认识。
- 由于抽象概念并不利于理解,同样我们利用递归调用中的经典问题——汉诺塔 来讨论递归调用。
- 我常常认为,代码是思想的映射。所以对于递归的认识,思想上的理解是大于复刻代码的能力的。
汉诺塔的规则
1.一次只能移动一个圆盘
2.圆盘可以插在X,Y和Z中的任一塔座上
3.任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。
三阶汉诺塔问题
要解决三阶汉诺塔问题,我们需要先解决二阶汉诺塔问题
相信大家都觉得二阶汉诺塔很简单吧。将Y塔柱当作辅助塔,先移动最上层圆盘到辅助塔,然后移动非最上层圆盘到目标塔,最后将辅助塔上的上层圆盘放到目标塔即可。
汉诺塔的规律我们已经找到了,就是将第1层圆盘放到辅助塔,第一层以下的圆盘放置到目标塔,最后将第一层圆盘放到目标塔即可。
因此我们可以写出代码
void hanoi(int n,char x,char y,char z)
{
if(n=1)
move(x,1,z);
else
{
hanoi(n-1,x,z,y);
move(x,n,z);
hanoi(n-1,y,x,z);
}
}
实现步骤为
这里直接用严奶奶书上的图解。关于第一次的移动,1圆盘可以移动到c的原因是,在递归调用中,除了最外层函数外,其余所有被调用的函数型参在不断变化,因此在第一步移动的过程中,目标塔从c塔变成了b塔,而c塔变成了辅助塔。
递归函数的使用场景
若一个问题的解法与该问题的规模无直接关系,规模减小后问题的特征属性仍然一致,则可以使用递归。
递归工作栈
每一层递归信息被称为工作记录,其中包含上一层的入口地址和本层的数据。实际上,在调用下一层函数时,需要执行三步操作:
1.调用函数将实在参数与地址信息传给被调用函数
2.为被调用函数的局部变量分配存储空间
3.控制转移到被调用函数的入口
而被调用函数退出(退栈)也分为三步:
1.保存运算结果
2.释放数据区
3.根据上一层的入口地址转移控制。
理解了以上知识之后,相信你对栈和递归会有更加深刻的认识