菜鸟笔记
提升您的技术认知

二叉树的前序遍历,中序遍历,后序遍历

这三也是经典的二叉树的三种方法

二叉树的前序遍历

递归实现

public class Main4 {
	static ArrayList<TreeNode> list = new ArrayList<TreeNode>();
	int QianXu(TreeNode t) {
	//根,判定第一个节点(根)是否存在
		if(t==null) {
			return 0;
		}	
		list.add(t);
		//左
		if(t.left!=null) {			
			HouXu(t.left);	
		}	
		//右
		if(t.right!=null) {		
			HouXu(t.right);
		}
		
		return 0;
		
	}
	
	public static void main(String[] args) {

		TreeNode tn1= new TreeNode(1);
		TreeNode tn2= new TreeNode(2);
		TreeNode tn3= new TreeNode(3);
		TreeNode tn4= new TreeNode(4);
		TreeNode tn5= new TreeNode(5);
		TreeNode tn6= new TreeNode(6);
		TreeNode tn7= new TreeNode(7);
		tn1.left=tn2;
		tn1.right=tn3;
		tn2.left=tn4;
		tn2.right=tn5;
		tn3.left=tn6;
		tn3.right=tn7;
		new Main4().QianXu(tn1);
		for(int i =0;i<list.size();i++) {
			System.out.print(list.get(i).val);
		}
		
	
	}
}

这个没什么难理解的,顺序就是根,左,右节点,如果有左右节点就遍历,没有就不往左节点或右节点遍历了

非递归实现

前序遍历的非递归实现就不写了,很简单,和深度优先一样,我不知道别人有用什么奇怪方法的,但是我用栈来实现深度优先,可以参考二叉树广度优先搜索和深度优先搜索

二叉树的中序遍历

1、使用递归的方式实现

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
 }
public class Main3 {
	static ArrayList<TreeNode> list = new ArrayList<TreeNode>();
	int ZhongXuBianLi(TreeNode tn) {
		if(t==null) {  //判定第一个节点(根)是否存在
			return 0;
		}	
		//左
		if(tn.left!=null) {
			ZhongXuBianLi(tn.left);
		}	
		//根
		list.add(tn);
		//右
		if(tn.right!=null) {
			ZhongXuBianLi(tn.right);		
		}	
		return 0;
	}	
	public static void main(String[] args) {
		TreeNode tn1= new TreeNode(1);
		TreeNode tn2= new TreeNode(2);
		TreeNode tn3= new TreeNode(3);
		TreeNode tn4= new TreeNode(4);
		TreeNode tn5= new TreeNode(5);
		TreeNode tn6= new TreeNode(6);
		TreeNode tn7= new TreeNode(7);
		tn1.left=tn2;
		tn1.right=tn3;
		tn2.left=tn4;
		tn2.right=tn5;
		tn3.left=tn6;
		tn3.right=tn7;
		new Main3().ZhongXuBianLi(tn1);
		for(int i =0;i<list.size();i++) {
			System.out.print(list.get(i).val);
		}
		
	}
}

结果:

使用的例子示例图

分析这个可能有点眼花缭乱,那就先看小的部分

这个怎么能成中序遍历呢?
肯定是213吧,那是不是先把2节点放进去,再把1节点放进去,再把三节点放进去呢!肯定的
那给的节点肯定是1节点了,那访问的顺序肯定就是先从1到2,再经过1到3。
而这个顺序正好有一个中序遍历的顺序,那就是213,所以就从2节点开始放,那怎么知道到2了呢?
那就找左子树是null的节点就行,添加完2肯定就是返回,返回到根节点添加1,再通过右子树为null找到3,添加进去,就完成了。
再经过递归就可以成大的了、

2、使用非递归的方式实现(使用栈)

TreeNode是二叉树的节点,上个程序有,这就不添加上了

	//非递归
	int ZhongXuBianLi1(TreeNode tn) {
		//根不存在
		if(tn==null) {
			return 0;
		}	
		Stack<TreeNode> stack = new Stack<TreeNode>();	
		stack.add(tn);
		//isEmpty只有当size==0时才返回true
		while(stack.isEmpty()==false) {		 //第一步
			if(tn!=null) {						//第二步
				stack.add(tn);
				tn = tn.left;			
			}else {									//第三步
				tn = stack.pop();
				list.add(tn);			
				if(stack.isEmpty()==false) {			//第四步
					tn = stack.pop();
					list.add(tn);				
				}
				tn = tn.right;			
			}			
		}		
		return 0;
		}	
	public static void main(String[] args) {
		TreeNode tn1= new TreeNode(1);
		TreeNode tn2= new TreeNode(2);
		TreeNode tn3= new TreeNode(3);
		TreeNode tn4= new TreeNode(4);
		TreeNode tn5= new TreeNode(5);
		TreeNode tn6= new TreeNode(6);
		TreeNode tn7= new TreeNode(7);
		tn1.left=tn2;
		tn1.right=tn3;
		tn2.left=tn4;
		tn2.right=tn5;
		tn3.left=tn6;
		tn3.right=tn7;
		new Main3().ZhongXuBianLi1(tn1);
		for(int i =0;i<list.size();i++) {
			System.out.print(list.get(i).val);
		}
		
	}

这个的例子也是用的

因为不是用递归实现,所以就需要用while或者for来代替递归了,说实话递归的确好理解

一步一步的来分析分析怎么用栈来解决的,用栈怎么实现的。
首先看一张图

不知道你能不能看懂,一开始我也看不懂,经过自己写这个过程就会了,
这些不同颜色的实线箭头 就是进栈的顺序(这些箭头是不可以打断的,比如1,2,4必须进栈是1、2、4,不能在4之前插入一个)
当然出栈的没写,根据入栈的顺序,和中序遍历的顺序结合,其实就能写出 出栈的顺序。

按这个思路,首先你需要while循环一下把1、2、4都添加进去吧,之后出4,2,再把5进栈
之后5,1出栈,3、6进栈,再3、6出栈,7入栈,再7出栈,就构成了中序遍历

上面的思路好理解,但是实现有点困难,看程序,
1、首先解决的是while的判定条件,因为这个过程中栈空代表着么有没有节点了,所以结束了,
2、之后是怎么一口气把像1、2、4这样的节点入栈
3、什么情况下开始出栈,出栈几个(要考虑到有可能连着的父节点,祖父节点等没有右节点),
4、考虑到出栈到根节点的情况
上面的4个正好对应程序中关键的四步

二叉树的后序遍历

递归实现

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
 }
public class Main4 {
	static ArrayList<TreeNode> list = new ArrayList<TreeNode>();
	int HouXu(TreeNode t) {
		if(t==null) {  //判定第一个节点(根)是否存在
			return 0;
		}	
		//左
		if(t.left!=null) {			
			HouXu(t.left);	
		}		
		//右
		if(t.right!=null) {		
			HouXu(t.right);
		}
		list.add(t);	
		return 0;
		
	}
	
	public static void main(String[] args) {

		TreeNode tn1= new TreeNode(1);
		TreeNode tn2= new TreeNode(2);
		TreeNode tn3= new TreeNode(3);
		TreeNode tn4= new TreeNode(4);
		TreeNode tn5= new TreeNode(5);
		TreeNode tn6= new TreeNode(6);
		TreeNode tn7= new TreeNode(7);
		tn1.left=tn2;
		tn1.right=tn3;
		tn2.left=tn4;
		tn2.right=tn5;
		tn3.left=tn6;
		tn3.right=tn7;
		new Main4().HouXu(tn1);
		for(int i =0;i<list.size();i++) {
			System.out.print(list.get(i).val);
		}
		
	
	}
}

非递归实现

用两个栈来实现,当压入第一个栈是1,取出来把它左右都压进栈,再把1压入另一个栈,这样循环下去,第二个栈的出栈顺序就是后续遍历

int HouXu1(TreeNode t) {
		if(t==null) {
			return 0;
		}
		Stack<TreeNode> stack1=new Stack<TreeNode>();
		Stack<TreeNode> stack2=new Stack<TreeNode>();
		stack1.add(t);
		while(!stack1.isEmpty()) {
			t =stack1.pop();
			if(t.left!=null) {
				stack1.add(t.left);
			}
			if(t.right!=null) {
				stack1.add(t.right);
			}
			stack2.add(t);
		}
		while(!stack2.isEmpty()) {
			list.add(stack2.pop());
		}
		return 0;
	}
	
	public static void main(String[] args) {

		TreeNode tn1= new TreeNode(1);
		TreeNode tn2= new TreeNode(2);
		TreeNode tn3= new TreeNode(3);
		TreeNode tn4= new TreeNode(4);
		TreeNode tn5= new TreeNode(5);
		TreeNode tn6= new TreeNode(6);
		TreeNode tn7= new TreeNode(7);
		tn1.left=tn2;
		tn1.right=tn3;
		tn2.left=tn4;
		tn2.right=tn5;
		tn3.left=tn6;
		tn3.right=tn7;
		new Main4().HouXu1(tn1);
		for(int i =0;i<list.size();i++) {
			System.out.print(list.get(i).val);
		}
		
	
	}

分析分析这三种遍历中递归的区别(非递归联系不是很大)

自己整理完这三种遍历的算法,感觉也就那样,尤其是递归的,更没什么

		if(t==null) {		//这个必须排第一个
			return 0;
		}								
		list.add(t);		//第一部分
		//左
		if(t.left!=null) {			//第二部分
			HouXu(t.left);	
		}	
		//右
		if(t.right!=null) {		 //第三部分
			HouXu(t.right);
		}
		return 0;

前序遍历、中序遍历、后序遍历也就是上面三部分根据前面序列的规则排序而已。
举个例子:
前序要求根节点,左节点,右节点。那上面排序的规则就是第一部分(根)、第二部分(左)、第三部分(右)

很简单。看别人千万遍不如自己写一遍,总结一遍啊。