经典数据结构--二叉树的遍历
递归遍历二叉树只有三行代码,特别容易理解且特别容易实现,但是非递归就没有那么的一目了然,不过其实就是把递归的做法平铺开来而已。下面来看每一种顺序的做法。
先序遍历:也就是先访问根节点,再左孩子,再右孩子。如何做呢,用手在纸上画一颗简单的二叉树,你会发现,先序遍历的顺序就是从根节点开始,一直访问左孩子,直到叶子(无孩子),然后访问这个叶子的父亲的右孩子(可能是子二叉树,不一定是一个单独的节点),祖先的右孩子......,然后就结束了。
在实现的时候可以用这样的方法:
1.声明一个栈,从根节点开始访问当前节点(设为temp),并将其入栈;
2.判断结点temp的左孩子是否为空,若为空,则出栈,并将栈顶结点的右孩子赋值给新的当前结点temp,循环至1 ;若不为空,将当前节点的左孩子赋值给新的当前结点temp
3.循环到栈为空且当前节点temp也为空结束遍历
代码:
public void preOrderTraversal(Node root) {
Stack<Node> s = new Stack<Node>();
Node temp = root;
while (temp != null || !s.isEmpty()) {
while (temp != null) {
System.out.print(temp.value + " ");
s.push(temp);
temp = temp.left;
}
if (!s.isEmpty()) {
temp = s.peek();
s.pop();
temp = temp.right;
}
}
}
中序遍历:也就是把根节点放在中间访问,先访问左孩子,再根节点,再右孩子这样的顺序。
实现方法:
其实只要对先序遍历做一行代码的移动就可以,原先是先访问再入栈,现在变成先入栈,等到出栈的时候再访问,就可以实现。
代码:
public void inOrderTraversal(Node root) {
Stack<Node> s = new Stack<Node>();
Node temp = root;
while (temp != null || !s.isEmpty()) {
while (temp != null) {
s.push(temp);
temp = temp.left;
}
if (!s.isEmpty()) {
temp = s.peek();
System.out.print(temp.value + " ");
s.pop();
temp = temp.right;
}
}
}
后序遍历:也就是根节点最后被访问,先左孩子,再右孩子,最后根节点的顺序。
实现的时候要稍微复杂一点:
用手画一棵树,可以发现,后续遍历,每一次访问的节点的共同特点是“没有孩子”,打上引号的原因是这个没有孩子包含两种情况,一种是叶子节点,也就是真的没有孩子节点,当然是可以直接访问的,还有一种是左孩子和右孩子(不管有一个还是两个)都被访问过了,才可以被直接访问。
那么实现的时候就可以按照下面的代码来:
用cur记录当前节点,pre记录上一次访问的节点。
1.如果cur的左右都空,那么访问;
2.如果pre不为空,也就是上一次有访问,且pre是cur的左孩子或者右孩子,就访问cur,且出栈,pre=cur;
3.如果其他情况,先入栈右孩子,再入栈左孩子,这样出栈的时候就是先左后右
4.循环直到栈为空
代码:
public static void postOrderTraversal(Node root) {
Stack<Node> s = new Stack<Node>();
Node cur;
Node pre = null;
s.push(root);
while (!s.isEmpty()) {
cur = s.peek();
if ((cur.left == null && cur.right == null)
|| (pre != null && (cur.left == pre || cur.right == pre))) {
System.out.print(cur.value + " ");
s.pop();
pre = cur;
} else {
if (cur.right != null)
s.push(cur.right);
if (cur.left != null)
s.push(cur.left);
}
}
}