数据结构--树的非递归遍历

主宰稳场 提交于 2019-11-28 22:33:42

    树的递归遍历代码非常简单易懂,但是由于递归会占用非常多的栈空间,因此非递归的遍历树也是必须要掌握的。因此最近仔细分析了很多的代码以及理解了遍历的过程,最后敲一遍并在这里记录一下,以后可以快速回顾。一般来说,递归可以解决的问题也一定可以用栈加循环的方式解决,毕竟递归实质上就是利用了栈嘛。

 

树从根节点开始对每个结点进行遍历,每个结点必定被访问三次,如上图。

第一次碰到就访问就是先序,第二次碰到访问就是中序,第三次碰到访问就是后序。

public class Tree {

    public void preOrder(TreeNode t) {  //先序遍历
        Stack<TreeNode> s = new Stack<>();
        while(t != null || !s.isEmpty()) {
            while(t != null) {
                System.out.println(t.val);  //第一次碰到就访问结点
                s.push(t);                //压栈保存,以便左边访问完了,可以得到此结点的右节点
                t = t.left;
            }
            if(!s.isEmpty()) {
                t = s.pop();
                t = t.right;      //当上述循环推出,说明左子树全访问完了,则把父结点弹出,准备访问右子树
            }
        }
    }

    public void inOrder(TreeNode t) {  //中序,与先序很像,只是在第二次碰到结点才访问
        Stack<TreeNode> s = new Stack<>();
        while(t != null || !s.isEmpty()) {
            while(t != null) {
                s.push(t);      //第一次碰到不访问,只保存
                t = t.left;
            }
            if(!s.isEmpty()) {
                t = s.pop();
                System.out.println(t.val);    //左子树访问完了,弹出父结点,第二次碰到则访问
                t = t.right;            //准备访问右子树
            }
        }
    }

    public void lastOrder(TreeNode t) {  //与上述两种方式有区别,只有左右结点都被访问,当前结点才能被访问
        TreeNode preNode = null;
        Stack<TreeNode> s = new Stack<>();
        s.push(t);    //压入根节点,这货铁定最后访问,万年栈底元素
        while(!s.isEmpty()) {
            TreeNode current = s.peek(); //获取栈顶元素

            //当前结点左右结点均为空,或都已经被访问
            //由于压栈顺序是先右后左,所以当前结点的孩子们访问时必然是先左后右 preNode == left说明当前结点只有左孩子,==right说明左右均已访问
            if((current.left == null && current.right == null) || (preNode != null && (preNode == current.left || preNode == current.right))) {
                System.out.println(current.val);
                s.pop();  
                preNode = current;  //每访问一个结点都记录一下,以便下次判断上次当前结点的左右孩子是否已被访问
            }
            else if(current.right != null)  //若不满足上述条件,则把当前结点的孩子以先右后左的顺序压栈,这样访问时就是先左后右了
                s.push(current.left);
            else if(current.left != null)
                s.push(current.right);
        }
    }

}

class TreeNode {

    TreeNode left;
    TreeNode right;
    int val;

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

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!