二叉树的先序、中序、后序遍历

分别可以用递归的方式和非递归的方式实现

代码实现 

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();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值