小白都能看懂的-二叉树后序遍历(递归和自定义栈)

小白都能看懂的-二叉树后序遍历(递归和非递归)

递归解决:


/**
 * 二叉树的后序遍历
 * @author Administrator
 *
 */
public class TwoChaTree {
	
	/**首先我们要明白二叉树后序遍历的定义?  先左在右最后根。 如下例子后序遍历结果为:3 2 2 1
	 *   举个栗子:二叉树
	 * 	 1
	 *  2 2
	 * 3
	 */ 
	public List<Integer> postorderTraversal(TreeNode root) {
		List<Integer> list = new ArrayList<>();
		postorderTraversal(root, list);
		System.out.println(list);
		return list;
	}
	private void postorderTraversal(TreeNode treeNode, List<Integer> list) {
		if(treeNode == null) {
			return;
		}
		/**
		 *  在下一行代码,我们不断的调用postorderTraversal()方法,以下简称p()方法
		 *  	第一次调用	p(treeNode.left, list) :p(2, []),treeNode != null  // 为了简写这里的2代表 下一个treeNode的val
		 *  	第二次调用 	p(treeNode.left, list) :p(3, []),第三次执行p()
		 *  	这时treeNode == null,执行return,我们返回到第二次调用postorderTraversal(),
		 *  	说明p(treeNode.left, list)这个方法已经执行完毕(很多人会卡在这里)
		 *  	接着我们继续执行	p(treeNode.right, list) :treeNode.val = 3,treeNode.right = null作为参数
		 *  	调用p(null,[]), return;
		 *  	这里说明我们第二次调用p(treeNode.right, list)执行完毕,这时p(3, []),来到 list.add(3)
		 *  	
		 *  	这里注意,执行完list.add(3),我们只代表执行完第二次调用p(treeNode.left, list)和p(treeNode.right, list)
		 *  	这里我们需要返回到第二次已经调用p(treeNode.left, list)剩下的p(treeNode.right, list):p(2, [3])再次执行 第三次次调用
		 *  	p(treeNode.right, list): p(0,[3],这里return,返回第一次调用P(2,[3])并已经执行完毕,接着执行list.add(2)
		 *  
		 *  	这里同上,回到最初调用p(2, [3,2]);在执行list.add(2),这里postorderTraversal(treeNode.right, list)已经执行完毕,在执行list.add(1)
		 *  
		 *  	到这里就所有执行完毕
		 *  
		 *  	总结:能运行dbug运行一下
		 *  	
		 */
		postorderTraversal(treeNode.left, list); 
		postorderTraversal(treeNode.right, list);
		list.add(treeNode.val);
	}
	public static void main(String[] args) {
		TwoChaTree twoChaTree = new TwoChaTree();
		twoChaTree.postorderTraversal(new TreeNode(1, new TreeNode(2,new TreeNode(3),null), new TreeNode(2)));
	}
	

	

}


 class TreeNode {
	int val;
	TreeNode left;
	TreeNode right;

	public TreeNode(int val) {
		this.val = val;
	}

	public TreeNode(int val, TreeNode left, TreeNode right) {
		this.val = val;
		this.left = left;
		this.right = right;
	}
}

自定义栈

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
 * 二叉树的后序遍历
 * @author Administrator
 *
 */
public class TwoChaTree02 {
	private class Command {
		String s;
		TreeNode treeNode;
		
		public Command(String s, TreeNode treeNode) {
			this.s = s;
			this.treeNode = treeNode;
		}
	}

	
	/**首先我们要明白二叉树后序遍历的定义?  先左在右最后根。 如下例子后序遍历结果为:3 2 2 1
	 *  其次我们要明白栈的一个重要定义:元素先进后出  ,所以我们设计要先push根 在push右节点,最后push做节点
	 *   举个栗子:二叉树
	 * 	 1
	 *  2 2
	 * 3
	 */ 
	public List<Integer> postorderTraversal(TreeNode root) {
		List<Integer> list = new ArrayList<>();
		if(root == null) {
			return list;
		}
		Stack<Command> stack = new Stack<>();
		// 将栈push一个元素 : [0] s = "go",root 
		stack.push(new Command("go", root));
		
		while(!stack.isEmpty()) {
			/**
			 * 1.pop取出当前元素 
			 * 3.因为最后push先拿出来 , 第二次取 [2]{s = go,左节点} ,stack剩余两个元素
			 * 5取出最后一个元素[4]s = go,treeNode != null
			 * 7.取出最后一个元素[6]s = go,treeNode == null,然后再取一个元素[5]s = go,treeNode == null,再取一个元素 [4]s = visit
			 * 9取出最后一个元素[3] s= go,这时候取的是右节点null
			 * 11取到  第二层的右节点
			 * 12 取到null 取到null 取到visit list.add(2) 最后list.add(1)
			 */
			Command command = stack.pop();
			if("visit".equals(command.s)) {
				/**
				 * 8.list.add(3)
				 * 10 list.add(2)
				 */
				list.add(command.treeNode.val);
			}
			/**
			 * 	2.第一次push三个元素 [0] {s = visit,对象} [1]{s = go,右节点}  ,[2]{s = go,左节点}   相当于 1 2 2 
			 *  4.根据例子 stack继续增加三个元素 2 3 null
			 *  6根据例子 stack继续增加三个元素 3 null null
			 *  12 根据例子 stack继续增加三个元素 2 null null
			 */
			if("go".equals(command.s) && command.treeNode != null) {
				stack.push(new Command("visit", command.treeNode));
				stack.push(new Command("go", command.treeNode.right));
				stack.push(new Command("go", command.treeNode.left));
			}
		}
		System.out.println(list);
		return list;
	}
	
	public static void main(String[] args) {
		TwoChaTree02 twoChaTree = new TwoChaTree02();
		twoChaTree.postorderTraversal(new TreeNode(1, new TreeNode(2,new TreeNode(3),null), new TreeNode(2)));
	}

}

总结:开始不理解的话慢慢跟着dbug走,然后跟着我的注释,相信你很快就会弄懂的,还有这两种方法对前序和中序也同样适用哦!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值