前言
本篇文章介绍二叉树的几种遍历方法:前序遍历、中序遍历、后序遍历和层序遍历。
包含递归和非递归遍历。
二叉树表示
结点表示,构造二叉树
public class BiNode {
public String data;
public BiNode lChild;
public BiNode rChild;
public BiNode(String data) {
this.data = data;
}
}
1. 前序遍历(根左右)
// 递归
static void preOrderRe(BiNode tree) {
if (tree == null) return;
System.out.print(tree.data);
preOrderRe(tree.lChild);
preOrderRe(tree.rChild);
}
// 非递归遍历,使用栈
static void preOrder(BiNode tree) {
if (tree == null) return;
Stack<BiNode> stack = new Stack<>();
stack.push(tree);
while (!stack.empty()) {
BiNode node = stack.pop();
System.out.print(node.data);
if (node.rChild != null) {
stack.push(node.rChild);
}
if (node.lChild != null) {
stack.push(node.lChild);
}
}
}
// 非递归遍历,先存储所有左子结点,回溯取右结点
static void preOrder2(BiNode tree) {
if (tree == null) return;
Stack<BiNode> stack = new Stack<>();
while (tree != null || !stack.empty()) {
if (tree != null) {
//遍历完左子树,全部存入栈内
System.out.print(tree.data);//打印根节点
stack.push(tree);
tree = tree.lChild;
} else {
// 左节点到底了,回溯取右节点
tree = stack.pop();
tree = tree.rChild;
}
}
}
2. 中序遍历(左根右)
static void inOrderRe(BiNode tree) {
if (tree == null) return;
inOrderRe(tree.lChild);
System.out.print(tree.data);
inOrderRe(tree.rChild);
}
static void inOrder(BiNode tree) {
if (tree == null) return;
Stack<BiNode> stack = new Stack<>();
while (tree != null || !stack.isEmpty()) {
if (tree != null) {
stack.push(tree);
tree = tree.lChild;
} else {
BiNode pop = stack.pop();
System.out.print(pop.data);
tree = pop.rChild;
}
}
}
3. 后序遍历(左右根)
static void postOrderRe(BiNode tree) {
if (tree == null) return;
postOrderRe(tree.lChild);
postOrderRe(tree.rChild);
System.out.print(tree.data);
}
/*
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。
如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。
若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
*/
static void postOrder(BiNode tree) {
if (tree == null) return;
Stack<BiNode> stack = new Stack<>();
stack.push(tree);
BiNode pre = null;
//push时候按照根右左入栈
while (!stack.empty()) {
BiNode cur = stack.peek();
if ((cur.lChild == null && cur.rChild == null) ||
(pre != null && (pre == cur.rChild || pre == cur.lChild))) {
//左右结点都是空 || 左右结点都被访问过(先判断右结点)
System.out.print(cur.data);
stack.pop();
pre = cur;
} else {
if (cur.rChild != null) {
stack.push(cur.rChild);
}
if (cur.lChild != null) {
stack.push(cur.lChild);
}
}
}
}
//用两个栈
static void postOrder2(BiNode tree) {
if (tree == null) return;
Stack<BiNode> stack = new Stack<>();
Stack<BiNode> output = new Stack<>();
stack.push(tree);
//output按照根右左入栈,stack按照根左右入栈
while (!stack.empty()) {
BiNode pop = stack.pop();
output.push(pop);
if (pop.lChild != null) {
stack.push(pop.lChild);
}
if (pop.rChild != null) {
stack.push(pop.rChild);
}
}
while (!output.empty()) {
System.out.print(output.pop().data);
}
}
4. 层序遍历
// 使用队列,一端进、一端出
static void levelOrder(BiNode tree) {
if (tree == null) return;
Queue<BiNode> queue = new LinkedList<>();
int nodesInCurrentLevel = 1, nodesInNextLevel = 0;
queue.offer(tree);
while (!queue.isEmpty()) {
BiNode node = queue.poll();
--nodesInCurrentLevel;
if (node != null) {
System.out.print(node);
if(node.lChild != null){
queue.offer(node.lChild);
++nodesInNextLevel;
}
if(node.rChild != null){
queue.offer(node.rChild);
++nodesInNextLevel;
}
}
if (nodesInCurrentLevel == 0) {
nodesInCurrentLevel = nodesInNextLevel;
nodesInNextLevel = 0;
}
}
}
> 参考: [二叉树的非递归遍历](http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html) [二叉树遍历之非递归算法](http://blog.csdn.net/sgbfblog/article/details/7773103)