穿脱原理:穿了T恤、背心、夹克,先脱夹克再脱背心最后脱T恤。
void p (参数表) {
if (递归结束条件)可直接求解步骤;-----基本项
else p(较小的参数);------归纳项
}
在求解6的阶乘时,递归过程如下所示。
image.png
我们会惊奇的发现这个过程和栈的工作原理一致对,递归调用就是通过栈这种数据结构完成的。整个过程实际上就是一个栈的入栈和出栈问题。然而我们并不需要关心这个栈的实现,这个过程是由系统来完成的。
那么递归中的“递”就是入栈,递进;“归”就是出栈,回归。
二叉树的结点结构是:
1、根结点(存放结点数据)
2、左子树指针
3、右子树指计
对二叉树的遍历就是访问各个结点中根结点里存放的数据。例如:
如果结点A有左结点B,右结点C,记作A(B,C),不同结点我用""隔开。那么有这样一个(BitTree)二叉树表A(B,C) \B(D,E)\E(F.G)\C(空,H)\H(I.空), 自己画出来,不然我后面白讲了。
要想把所有的数据都访问到则必需按照一定的原则,即当前结点的下一个结点是哪个结点。
无论是先、中还是后序算法都是先将左结点视为下一个结点,当左结点不存在(即为空时)才将右结点视作下一个结点,如果右结点也不存在就返回当前结点的上层结点再向右访问,如此类推。
于是对二叉树的遍历问题就被抽象成三个基本步骤:
1、访问根结点。
2、访问该点的所有左子树。
3、访问该点的所有右子树。
先序遍历的策略是按123的步骤执行,中序是按213来,后序则是231,它们之间的不同只是“访问根结点”在这三个步骤中的位置。
看着你刚画好的那个BitTree跟着我的思路走。在先序遍历算法PriorOrder中,先将BitTree的头结点A传进来,按步骤123的处理。123是抽象实现,记住所表达的思想,下面是具体实现。为了避免混乱用中文数字记录步骤。
一、即是读取结点A的数据内容A(此时A为当前函数处理结点),将A的右结点C放入栈S中,S中的内容为S(C)[注意这一步是算法的一个辅助,并不是先向右访问,下同],将左结点B传给PriorOrder处理。此时读取了A
二、读取B的内容B(此时B为当前结点),将B的右结点E放入S中,S中的内容为S(C,E),将B的左结点D传给PriorOrder处理。此时读取了AB
三、D为当前结点,D的右为空没有东西放入S,S中的内容仍为S(C,E),D的左也为空,没有访问可访问的。此时就从S中取出E(因为栈是先进后出的所以取的就是E,此时S中的内容为S(C),正好是上一层没访问过的右子树),将E传给PriorOrder处理。此时读取了AB D
四、E为当前结点,对于结点E类似的有S(C,G),读取了ABDE,将F传入PriorOrder
五、F为当前结点,右为空,左也为空,读取了ABDEF,从栈中取出G传给PriorOrder处理,S的内容为S(C);
六、类似的读取了ABDEFG,从S中取出了C,传给PriorOrder处理。此时S()。
七、当前结点为C,从将C的右结点放入S,S中内容为S(H),C的左为空,从S取出H,将H传给PriorOrder处理。此时S为S().于是就读取了ABDEFGC
八,类似的读取了ABDEFGCH
九,最后ABDEFGCHF
你再对照的书上的算法想想,画画就应该能明白点。特别要理角的一点是为什么用递归算法时计算机能按这样的方式是因为函数调用是“先调用,后执行完”,或者说“后调用,先执行完”。注意我加一个“完”字
全局变量当作参数递归,也会回溯。
参考
https://blog.csdn.net/wait_for_taht_day5/article/details/50174725
https://www.cnblogs.com/klguang/p/5463137.html
网友评论