Java——二叉树非递归遍历方式(Leecode144/94/145)

(一)了解递归实现前序遍历的底层原理

对于二叉树最经典的就是前中后序遍历的递归实现。以前序遍历为例,宏观来看,只要当前节点不为空,就将当前节点存入list,遍历左子树遍历右子树。最终即可完成整棵树的遍历。
通过java代码实现一棵二叉树的遍历,代码如下:

public class TreeNode {
     int val;
     TreeNode left;
     TreeNode right;
     TreeNode(int x) { val = x; }
 }
Class Solution{
	List<Integer> list = new ArrayList<Integer>();
	public List<Integer> preorderTravel(TreeNode root){
		if(root!=null){
			list.add(root.val);
			preorderTravel(root.left);
			preorderTravel(root.rigth);
		}
		return list;
	}
}

来分析一下,系统内部的运行,以下面这个简单的二叉树的前序为例:
在这里插入图片描述
那首先知道系统中的所有递归遍历都是通过系统栈来实现的,而栈这种数据结构特点是先进后出。所以我们要前序遍历当前这棵树他的顺序应该是,访问当前节点1的值,访问左子树,访问右子树。对应的入栈顺序就是,访问右子树、访问左子树、访问节点1。我们将访问指令定义为print,访问左子树指令定义为left,访问右子树指令定义为right。
那么访问1节点其栈内信息如图:
访问节点1系统站内指令
此时开始第一步访问,print出栈,没有后续操作,那么继续出栈,left1访问当前节点左子树。此时,需要将左子树的访问顺序入栈,系统栈信息如图:
在这里插入图片描述
此时系统无操作继续访问系统栈,取出第一条指令,print2填入list无操作。再取出来left2,此时转向节点2的左子树,而其为空直接返回当前系统栈。所以再从系统栈取出right2,同样他的左右子树都为空也直接返回。此时系统栈信息如图:
在这里插入图片描述
取出right1,此时其节点不为空,那么将right1对应操作存入系统栈:
在这里插入图片描述
再取出第一条指令,print3,添加到list后,无后续操作。再取出left3,3节点左子树为空直接返回。再取出right3,3节点右子树为空直接返回。再取系统栈指令,系统栈为空。遍历结束:
在这里插入图片描述
从上述过程可以看出,系统栈存储着访问指令,是输出指令还是转向左子树或者右子树进行执行指令。当输出指令,直接输出,再取指令,此时取出来的转向指令出栈后,若访问的节点不为空,则将访问节点的3条访问指令入栈即可。一直按照这种顺序去访问系统栈,直到栈中没有指令,二叉树的递归遍历也就结束了。

(二)模拟系统栈完成二叉树非递归遍历

除了教课书给出的经典的非递归方式外,我们总结一下另一种方式——模拟系统栈,来完成二叉树的非递归操作。
根据上面的步骤,我们需要建立栈(存储指令)和指令来辅助完成该程序。

public class Commond {
     String s;//指定信息,print or go(go left ,go rigth)
     TreeNode node;
     Commond(String s, TreeNode node) {this.s= s;this.node = node;}
 }
 class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
    	List<Integer> list = new ArrayList<Integer>();//存二叉树节点信息
    	if(root == null)
    		return list;
    	//模拟系统栈,存储指令信息
    	Stack<Commond> stack = new Stack<Commond>();
    	//设置初始值位当前节点
    	stack.push(new Commond("go",root));
    	//栈不为空的时候循环访问,取指令
    	while(!stack.isEmpty()){
			Commond cd = stack.pop();
			//如果是访问指令,直接存入集合中
			if(cd.s == "print")
				list.add(cd.node.val);
			else{
			//注意入栈的顺序奥
				if(cd.node.rigth!=null)
					stack.push(new Commond("go",cd.node.rigth));
				if(cd.node.left!=null)
					stack.push(new Commond("go",cd.node.left));
				stack.push(new Commond("print",cd.node));
			}
		}
		return list;
    }
  }

以上就是对leecode144号问题,二叉树前序遍历的递归和非递归实现方式。呐对于94和145两个问题。仅需要改变上面代码的顺序就OK啦。那下一篇文章将会介绍二叉树递归遍历的一些题目~要加深递归遍历的宏观理解奥

(三)教科书通过stack完成二叉树的非递归遍历

下面给出教科书中,通过stack完成二叉树的非递归前序遍历。对于中序遍历和后续遍历,相对复杂,建议可以再理解(二)的基础上,通过二来实现。

public ArrayList<Integer> preOrder(TreeNode root) {
		//存储节点中的数据信息(遍历顺序)
        ArrayList<Integer> list = new ArrayList<>();
        //存储二叉树遍历过程中的节点
        Stack<TreeNode> stack = new Stack<>();
        //初始化
        stack.push(root);
        while(!stack.empty()){
            TreeNode treeroot = stack.pop();
            list.add(treeroot.val);
            //根据栈的特点,先添加右子树再添加左子树
            if(treeroot.right!=null){
                stack.push(treeroot.right);
            }
            if(treeroot.left!=null){
                stack.push(treeroot.left);
            }
        }
        return list;
    }
发布了16 篇原创文章 · 获赞 0 · 访问量 557

猜你喜欢

转载自blog.csdn.net/sunlili_yt/article/details/105310016