http://www.cnblogs.com/LZYY/p/3454778.html
在计算机科学里,树的遍历是指通过一种方法按照一定的顺序访问一颗树的过程。
对于二叉树,树的遍历通常有四种:先序遍历、中序遍历、后序遍历、广度优先遍历。(前三种亦统称深度优先遍历)对于多叉树,树的遍历通常有两种:深度优先遍历、广度优先遍历。
在学习前面三种深度优先遍历之前,很有必要了解它们之间到底是怎么遍历的,要自己去亲自去遍历,不要只看文字
先序遍历: 节点 - 左孩子 - 右孩子
中序遍历: 左孩子 - 根结点 - 右孩子
后序遍历 : 左孩子 - 右孩子 - 根结点
看下面的图(自己去写出几种遍历的情况):
按照上面的三种方法去遍历,结果是
前序遍历:- + a * b – c d / e f
中序遍历:a + b * c – d – e / f
后序遍历:a b c d – * + e f / -
广度优先遍历,又叫层次遍历:从二叉树的第一层(根结点)开始,自上至下逐层遍历;在同一层中,按照从左到右的顺序对结点逐一访问。
在这幅图里所的结果是:- + / a * c f b – c d
下面给出java实现上面几种遍历的算法以及解释:
三种递归的算法不说了,直接说非递归算法:
前序非递归实现
节点 - 左孩子 - 右孩子
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
有两种实现方法:
View Code
中序非递归算法:
左孩子 - 根结点 - 右孩子
*访问任意一节点p,若其左孩子非空,p入栈,且p的左孩子作为当前节点,然后在对其进行同样的处理
*若其左孩子为空,则输出栈顶点元素并进行出栈操作,访问该栈顶的节点的右孩子
*直到p为null并且栈为空则遍历结束
(和前序的非递归算法1_1有相似之处)
View Code
后序非递归算法
左孩子 - 右孩子 - 根结点
这个有难度 因为要保证左孩子和右孩子都已经被访问过了才访问根节点,这里就要思考一下如何标记一下右孩子是否已经被标记了。有两种方法:
双栈法(这个比较容易理解)
* 对于跟节点t,先入栈,然后沿着其左子树往下收索,直到没有左子树的节点,此时该节点入栈
* 但此时不能进行出栈访问,要检查右孩子,所以接下来一相同的规则进行处理,当访问其右孩子时,
* 该节点又出现在栈顶,此时就可以出栈访问,这样就保证了正确的访问顺序,这个过程中,
* 每个节点都两次出现在栈顶,只有在第二次出现在栈顶的时候才能访问它, 因此有必要设置两个栈
View Code
单栈法:
* 先扫描跟节点的所有左节点并入栈,接着将栈顶元素出栈,
* 再扫描该节点的右孩子节点并入栈,扫描右孩子的所有左节点并入栈,当一个节点的左右孩子均被访问后在访问该节点,
* 这里用一个初始值为null的节点表示右子树刚刚被访问的
* 一直到栈为空,这里的难点是如何判断右孩子已经被访问过了
这个构造真的是太赞了!!
View Code
另外一个单栈实现,单栈的构造都好神奇!
View Code
如果用数组去实现stack的话,可以用这个,这个是在求解两节点个最近公共祖先时用到的(LCA算法),改写自考研书上
View Code
下面是全部的代码外加一个测试实例:
View Code
网上有好的很好的文章都有写道这几个搜索算法,这个博客是用c++实现的
http://www.blogjava.net/fancydeepin/archive/2013/02/03/cpp_binarytreesearch.html