关于树的递归和迭代遍历方法
最近在看csdn解题笔记系列文章关于树的部分,卒读之后,扪心自问:二叉树到底有多少种便利方法?每种方法又有几中实现版本?各个版本间的关系如何,有无必然联系和转化可能?那天知道晚上一点多才有一些确定性的思考结果,总结如下。
一、树的递归遍历方法:略;
二、树的非递归遍历方法
(1)国内教材和网络流行的解法:二叉树的先根遍历,中根遍历,后根遍历的非递归算法 ;
(2)自己凭直觉想了一种先序方法[1],但无法对称地推广到中序、后序,便随便翻了下师弟给的一本电子书,Knuth大弟子Sedgewick的《算法:第1-4部分》,发现一种新的,思路比较统一的先序、中序、后序遍历的形式化非递归法描述:
1)对于根节点:
对于前序,入栈右子树,然后左子树,然后节点;
对于中序,入栈右子树,然后节点,然后左子树;
对于后序,入栈节点,然后右子树,然后左子树;
2)子树的入栈与上面是相同的,但是我们不使用递归;
三、层次遍历,除了流行的队列法,我设计了一种基于栈的方法(其实在模拟队列),用伪代码描述,参见[2]。
四、深入想下,递归和迭代的关系是什么?他们如何转化?
首先,请看扫盲文:
(1)尾递归对时间与空间复杂度的影响 ;
(2)尾递归与Continuation ;
(3)浅谈尾递归的优化方式 ;
得到结论:只要允许使用栈(也有人叫基于栈的非递归为递推,不列入迭代范畴),所有的递归程序都可以转化成迭代,反之则不然。但是并非所有递归都必须用栈。深入学习请参考:将递归转化成迭代的通用技术 。
五、附录:
[1]
root入栈
tag:
if (栈非空)
弹一次栈x,访问之;
if (x非叶子)
x右子树入栈;
x左子树入栈;
goto tag;
结束;
[2]
root入栈;
if 栈(a,b,c...)非空
连续弹栈,直至为空,得到出栈元素xi(...c,b,a);
按出栈次序,访问xi;
if(xi非叶子)
xi右子树入栈;
xi左子树入栈;
结束;