二叉树遍历系列01-递归遍历与递归序
一、引言
-
先序遍历
先序遍历又名先根遍历,顾名思义,在这种遍历方法中,首先遍历根结点,然后再先序遍历根节点的左孩子,之后先序遍历根节点的右孩子,从这个遍历规则中,我们可以看出,有很明显的递归意味,因此使用递归方法实现树的先序遍历是一种常见的方法,非常简单
-
中序遍历
中序遍历,和先序遍历不同的是,中序遍历并不是先访问根节点,中序遍历先访问根节点的左孩子,然后访问根节点,最后访问根节点的右孩子,这个中的意思也就很明显了,就是把根节点的遍历放在左孩子和右孩子的中间
-
后序遍历
有了先序遍历和中序遍历的介绍之后,后序遍历就显得很直白了,先访问根结点的左孩子,接着访问根节点的右孩子,最后访问根,虽然后序遍历听着和先序以及中序一样简单,实际上后续遍历的递归实现也很简单,但是后序遍历的非递归实现却是最复杂的
二、三种遍历递归实现
2.1 先序遍历
public void preOrder(TreeNode root) {
if (root == null) {
return;
}
Systen.out.println(root.val);
preOrder(root.left);
preOrder(root.right);
}
2.2 中序遍历
public void inOrder(TreeNode root) {
if (root == null) {
return;
}
preOrder(root.left);
Systen.out.println(root.val);
preOrder(root.right);
}
2.3 后序遍历
public void postOrder(TreeNode root) {
if (root == null) {
return;
}
preOrder(root.left);
preOrder(root.right);
Systen.out.println(root.val);
}
三、递归写法的共性讨论
上述三种递归遍历可以写成如下这个样子
public void visit(TreeNode root) {
if (root == null) {
return;
}
// 如果在这处理,那么就是先序
visit(root.left);
// 如果在这处理,那么就是中序
visit(root.right);
// 如果在这处理,那么就是后序
}
3.1 递归图与递归序
我们可以画出上述
visit
的递归图,如下图所示,红色圆圈标注的是访问的顺序,其中null结点也需要被访问一次,我们根据上述递归访问的顺序,可以得到每一个元素的访问次序:1、2、4、7、7、7、4、4、2、5、5、5、2、1、3、3、6、6、6、3、1
,这就是递归序,通过观察递归序,我们可以发现,每一个元素都出现了三次,为什么呢,其实通过观察代码我们可以很容易得出这个结论:public void visit(TreeNode root) { if (root == null) { return; } // root第一次被访问 visit(root.left); // 前面一层递归结束后,又回到当前递归栈,root第二次被访问 visit(root.right); // root第三次被访问 }
也就是说,先序中序后序的遍历,本质上是一样的,区别就在于,在当前递归序中,某个元素第几次出现时进行该元素的处理,先序是在元素第一次出现的时候就处理,中序是元素第二次出现的时候就进行处理,后序就是元素最后一次出现的时候进行处理