二叉树是数据结构中的基础知识,也是面试笔试中的重要考点,在实际开发中也会用的比较多。要想解决二叉树相关的问题,就必须深刻理解二叉树的三种遍历六种算法!
(后序遍历递归方法的执行过程)
1.前序遍历
跟节点—>左子树—>右子树
对所有子树进行这样的遍历操作就得到前序遍历序列:DBACFEG
I.递归形式:先给出代码:
public void preorder_traversal_recursion(TreeNode root){
if (root==null)return;
System.out.print(root.val);
preorder_traversal_recursion(root.left);
preorder_traversal_recursion(root.right);
}
递归具有很强的描述能力所以代码很简短,但其抽象性很高,不便于理解前序遍历的原理。这里给出解释:
递归调用是基于栈完成的,每次自己调用自己时都会将当前状态压入递归栈,转而执行新被调用的方法,再调用自己时再压入栈,直到遇到递归出口return,最下层的函数执行完毕出栈,接着执行上一层未执行完的函数。
过程如下:
①读取D,进栈
②读取B,进栈
③读取A,进栈
④满足返回条件,root=null,出栈到B,接着C进栈,读取C
⑤满足root==null返回,出栈到B,B中函数体执行完毕,返回出栈到D,接着F进栈,读取F。遍历右子树和左子树类似,不再赘述。
非递归形式(迭代):其实迭代原理和上面的一模一样,只不过换用栈来代替递归。
①根节点左子树非空,一直进栈到左子树为空。这时,可以读取DBA
②左子树为空,那就看看又子树,出栈到B,C进栈,读取C,得到DBAC.又发现左子树为空,这时C左右子树均为空,出栈到D,接着右子树进栈。
public void preorder_traversal_iteration(TreeNode root){
if (root==null)return;
Stack<TreeNode> stack=new Stack<>();
TreeNode curr=root;
while (!stack.isEmpty()||curr!=null){
if (curr!=null){//一直进栈左子树节点,直到为null
System.out.print(curr.val);
stack.push(curr);
curr=curr.left;
}else {//左节点为空,则出栈选择右节点
curr=stack.pop().right;
}
}
}
2.中序遍历
把根节点放在中间遍历
左子树—>根节点—>右节点
即ABCDEFG(中序遍历在平衡二叉树运用的比较多,平衡二叉树的中序遍历是有序的,另外根据中序遍历序列和前序遍历序列或者后序遍历序列组合可以确定一个二叉树)
递归形式:
同样先上代码:
public void inorder_recursion(TreeNode root){
if (root==null)return;
inorder_recursion(root.left);
System.out.print(root.val);
inorder_recursion(root.right);
}
过程如下:
I.一直进栈,一直到左子树的最左端,出栈读取A
II.出栈,读取B,进栈发现C左子树为null,出栈读取C,发现C的右子树为空
出栈到D
III.出栈读取D,D的右子树不为空,则进入D的右子树,一直进栈到F的最左端。出栈读取E,出栈读取F,出栈读取G
迭代形式:
public void inorder_iteration(TreeNode root){
if (root==null)return;
Stack<TreeNode> stack=new Stack<>();
TreeNode curr=root;
while (!stack.isEmpty()||curr!=null){
if (curr!=null){
stack.push(curr);
curr=curr.left;
}else {
TreeNode t=stack.pop();
System.out.print(t.val);
curr=t.right;
}
}
}
I.前序遍历是在进栈的时候读取节点,中序遍历是在出栈的时候读取节点。
设置一个curr节点记录当前节点
从根节点开始,一直进栈到最左端,发现A的左子树为空,出栈,使curr=A.right,发现curr为空,出栈读取B,使curr=B.right。如此重复得到中序序列。
③后序遍历:
左子树—>右子树—>根节点
ACBEGFD
递归形式:
public void subsequent_traversal(TreeNode root){
if (root==null)return;
subsequent_traversal(root.left);
subsequent_traversal(root.right);
System.out.print(root.val);
}
后序遍历比前两种遍历稍微复杂一些
过程如下:递归方法的执行过程,顺着箭头方向
迭代形式:
public void subsequent_traversal_iteration(TreeNode root) {
if (root == null) return;
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
TreeNode pre = null;
while (!stack.isEmpty() || curr != null) {
if (curr != null) {
stack.push(curr);
curr = curr.left;
} else {
System.out.print(stack.pop());
curr = stack.peek().right;
}
}
}
ps:为了加深对二叉树遍历的理解,我们给出两个问题: