[数据结构]二叉树的各种遍历方式的Java实现

一.摘要

树的遍历有前序遍历,中序遍历,后续遍历三种方式,每种方式又有递归和非递归两种实现方法,以下是各种遍历方式的Java实现,这三种遍历方式的实现有下相同的点,递归的方法思路是比较清晰的,而非递归会稍微复杂一些,都需要用到栈的数据结构。
先定义树节点的结构

public class TreeNode()
{
	TreeNode left;//左孩子
	TreeNode right;//右孩子
	int val;//节点值
	//构造函数
	public TreeNode(int val)
	{
		this.val = val;
	}

}

二.前序遍历

顾名思义,遍历的顺序是先遍历根节点,如果有左孩子再遍历左节点,如果有右孩子再遍历右节点

2.1 前序遍历递归实现

代码:

public void  preOrderTraversal(TreeNode root)
{
	//先处理根节点
	if(root == null)
	{
		return ;
	}else
	{
		System.out.println(root.val);
	}
	//再处理左节点
	preOrder(root.left);
	//最后处理右节点
	preOrder(root.right);
}

2.2前序遍历非递归实现

用栈来实现,根节点不空则入栈,栈不空时做以下循环:
step1:当前节点出栈,打印它(访问它,遍历它),
step2:如果当前节点有右孩子,则右孩子入栈
step3:如果当前节点有左孩子,则左孩子入栈
Tips
为什么右孩子先入栈左孩子后入栈呢?因为栈是先进后出的,右孩子先进,左孩子后进,出栈的时候就会反过来,左孩子先出,右孩子后出,这就符合前序遍历的规律了

代码:

public void  preOrderTraversal(TreeNode root)
{
	if(root == null)
	{
		return;
	}
	//根节点不空时:
	Stack<TreeNode> s = new Stack<TreeNode>();//新建一个栈
	s.push(root);
	
	//栈不空时做以下循环
	while(!s.isEmpty())
	{	//出栈栈定元素
		TreeNode current  =  s.pop();
		System.out.println(current.val);
		//右孩子不空则进栈
		if(current.right!=null)
		{
			s.push(current.right);
		}
		//左孩子不空则进栈
		if(current.left!=null)
			{
				s.push(current.left);
			}
	}
}

三.中序遍历

遍历的顺序是如果有左孩子先遍历左节点,然后遍历根节点,如果有右孩子再遍历右节点。

3.1 中序遍历递归实现

代码:

public void  inOrderTraversal(TreeNode root)
{
	//根节点若不否为空
	if(root != null)
	{
		/先遍历左节点
		preOrder(root.left);
		//然后遍历根节点
		System.out.println(root.val);
		//最后遍历右节点
		preOrder(root.right);
	}
}

3.2中序遍历非递归实现

步骤:
1)申请一个新的栈
2)初始另cur=头节点,将cur压入,然后一直让cur=cur.left
3)当cur为空时,从栈中弹出节点它记为node并打印它的值,并让cur=node.right,重复步骤2)
4)当stack为空且cur也为空时,整个过程结束

代码:

public void  inOrderTraversal(TreeNode root)
{
	if(root == null)
	{
		return;
	}
	//根节点不空时:
	Stack<TreeNode> s = new Stack<TreeNode>();//新建一个栈
	TreeNode cur = root;
	//栈不空时做以下循环
	while(!s.isEmpty()||cur!=null)
	{	if(cur!=null)
		{
			s.push(cur);
			cur = cur.left;
		}else{
			TreeNode node = s.pop();
			System.out.println(node.val);
			cur = node.right;
		}
	}
}

四.后序遍历

遍历的顺序是如果有左孩子先遍历左节点,如果有右孩子再遍历右节点,最后遍历根节点。

4.1 后序遍历递归实现

代码:

public void  postOrderTraversal(TreeNode root)
{
	//根节点若不否为空
	if(root != null)
	{
		//先遍历左节点
		preOrder(root.left);
		//然后遍历右节点
		preOrder(root.right);
		//最后遍历根节点
		System.out.println(root.val);
	}
}

4.2后序遍历非递归实现

用s1,s2两个栈实现,步骤是:
step1: 将头节点压入s1,
step2: 从s1中弹出节点记作cur,然后把cur的左孩子压入s1,右孩子压入s1,
step3: 在这个过程中每弹出一个节点都放入s2中
不断重复步2,3直到s1为空,过程停止,从s2中依次弹出节点并打印,打印的顺序就是后续遍历的顺序
代码:

public void  postOrderTraversal(TreeNode root)
{
	if(root == null)
	{
		return;
	}
	//根节点不空时:
	//新建2个栈
	Stack<TreeNode> s1 = new Stack<TreeNode>();
	Stack<TreeNode> s2 = new Stack<TreeNode>();
	s1.push(root);
	
	//栈不空时做以下循环
	while(!s1.isEmpty())
	{	
		TreeNode cur  =  s1.pop();
		//弹出的节点放入s2
		s2.push(cur);
		//左孩子不空则进栈s1
		if(cur.left!=null)
		{
			s1.push(cur.left);
		}
		//右孩子不空则进栈s1
		if(cur.right!=null)
		{
			s1.push(cur.right);
		}
		
}
	//最后打印s2依次出栈的结果
	while(!s2.isEmpty())
	{	
		TreeNode result  =  s1.pop();
		System.out.println(result .val);
	}

这个方法真神奇,一个节点进了s2就可以带着他的的两个亲孩子进s1,控制好顺序就是后续遍历了,根先出s1,先进s2,可以保证根在后面,而每次只进左右孩子,保证了一个局部性,不会牵扯太多的元素,但每次就处理亲近的就刚刚好,太妙了。

五.给自己的问题(后续可能会更新)

能不能用两个栈来做中序遍历?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值