分别可以用递归的方式和非递归的方式实现
代码实现
package binaryTree;
import java.util.Stack;
/**
* 先序、中序、后序遍历二叉树(根左右、左根右、左右根)
* 具体来说,对于每个二叉树的递归序来说,每个节点其实都会经过3次,
* 只不过是做不做操作的区别。
* 递归序其实就是先序遍历走的路径,只不过详细化了它所有经过节点的次数
* 对于先序遍历来说,也就是在递归序中第一次经过该节点的时候打印该节点,另外两次经过的时候什么也不做
* 中序遍历:在递归序中第二次经过该节点的时候打印该节点,另外两次经过的时候什么也不做
* 后序遍历:在递归序中第三次经过该节点的时候打印该节点,另外两次经过的时候什么也不做
* @author zyt
*
*/
public class PreInPosTraversal {
/**
* 手动定义一个二叉树
* @author zyt
*
*/
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value = data;
}
}
/**
* 递归序遍历二叉树
* 借助这个理清楚经过节点的次数和时机
* @param head
*/
public static void f(Node head){
//第一次经过
if(head == null){
return;
}
//第一次经过
f(head.left);
//第二次经过
f(head.right);
//第三次经过
}
/**
* 前序遍历二叉树(递归实现)
* 只在第一次经过的时候打印节点的值
* @param head
*/
public static void preOrderRecur(Node head){
if(head == null){
return;
}
//只在第一次经过该节点的时候,打印它的值
System.out.print(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
/**
* 中序遍历(递归实现)
* 只在第二次经过节点的时候打印它的值
* @param head
*/
public static void inOrderRecur(Node head){
if(head == null){
return;
}
inOrderRecur(head.left);
//只在第二次经过该节点的时候,打印它的值
System.out.print(head.value + " ");
inOrderRecur(head.right);
}
/**
* 后序遍历(递归实现)
* 只在第三次经过节点的时候打印它的值
* @param head
*/
public static void posOrderRecur(Node head){
if(head == null){
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
//只在第三次经过节点的时候打印它的值
System.out.print(head.value + " ");
}
/**
* 先序遍历(非递归实现)
* 先准备一个栈,把头节点放进去
* 然后开始固定操作流程(只要栈不是空的就循环以下操作):
* 1、每次栈中弹出一个节点cur
* 2、打印(处理)cur
* 3、先把cur的右孩子压入栈,再把左孩子压入栈(如果有的话)
*
* @param head
*/
public static void preOrderUnRecur(Node head){
System.out.print("pre-order: ");
if(head != null){
//先准备一个栈,把头节点放进去
Stack<Node> stack = new Stack<>();
stack.add(head);
//只要栈不是空的就循环以下操作
while(!stack.isEmpty()){
//1、每次栈中弹出一个节点cur
head = stack.pop();
//
System.out.print(head.value + " ");
//先把cur的右孩子压入栈(如果有的话)
if(head.right != null){
stack.push(head.right);
}
//再把左孩子压入栈(如果有的话)
if(head.left != null){
stack.push(head.left);
}
}
}
System.out.println();
}
/**
* 后序遍历(非递归实现方法1)
* 先准备2个栈,第一个栈的作用同先序遍历,把头节点放进第一个栈,
* 只要第一个栈不为空,则循环以下操作:
* 1、每次第一个栈中弹出一个节点cur
* 2、将节点cur压入第二个栈中
* 3、先把cur的左孩子压入栈1,再把右孩子压入栈1(如果有的话)--》此处顺序与先序遍历相反
* 最后,第二个栈中的节点依次弹出,所得的结果就是后序遍历的结果
* @param head
*/
public static void posOrderUnRecur1(Node head){
System.out.print("pos-order: ");
if(head != null){
Stack<Node> s1 = new Stack<>();
Stack<Node> s2 = new Stack<>();
s1.push(head);
while(!s1.isEmpty()){
head = s1.pop();
s2.push(head);
if(head.left != null){
s1.push(head.left);
}
if(head.right != null){
s1.push(head.right);
}
}
while(!s2.isEmpty()){
System.out.print(s2.pop().value + " ");
}
}
System.out.println();
}
/**!!!这个方法需要背一下代码,代码很凝练,自己一般写不出来
* 中序遍历(非递归实现)
* 先准备1个栈,将整个树的左边界依次压入栈中
* (左边界是指从头节点开始,一路顺着左指针走下去所经过的节点)
* 循环以下操作:
* 1、栈中依次弹出弹出节点,打印节点值,
* 2、如果弹出的节点有右子树,则将其右子树的左边界又全部入栈,然后重复此操作
* 理解:所有树都可以是被左边界分解的,而且由于入栈的顺序是 头——>左,则出栈则会是 左——>头
* 又因为整体都是先遍历左子树,在遍历右子树,所以能够做到 左头右
* @param head
*/
public static void inOrderUnRecur(Node head){
System.out.print("in-order: ");
if(head != null){
//先准备1个栈
Stack<Node> stack = new Stack<>();
//当栈为空 且 当前节点为空 时,就结束循环
while(!stack.isEmpty() || head != null){
//将整个树的左边界压入栈中(对于右子树也是如此)
if(head != null){
stack.push(head);
head = head.left;
}else{
//栈中依次弹出弹出节点,打印节点值
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(5);
head.left = new Node(3);
head.right = new Node(8);
head.left.left = new Node(2);
head.left.right = new Node(4);
head.left.left.left = new Node(1);
head.right.left = new Node(7);
head.right.left.left = new Node(6);
head.right.right = new Node(10);
head.right.right.left = new Node(9);
head.right.right.right = new Node(11);
//recursive
System.out.println("================recursive===========");
System.out.print("pre-order: ");
preOrderRecur(head);
System.out.println();
System.out.print("in-order: ");
inOrderRecur(head);
System.out.println();
System.out.print("pos-order: ");
posOrderRecur(head);
System.out.println();
}
}