非递归实现二叉树的遍历

前序遍历

思路:
前序遍历就是先遍历一棵树的根节点,然后遍历左子树,再遍历右子树。要用非递归实现前序遍历,我们首先需要定义一个栈,再定义一个cur引用指向根节点。
只要cur不为空,就打印出cur的值,并且将cur指向的节点入栈。
在这里插入图片描述
cur引用一直向左走,直到走到null。在这里插入图片描述
然后将栈顶元素出栈,cur指向栈顶元素的右子树,如果cur为空,就接着出栈下一个栈顶元素,再去判断它的右子树是否为空,不为空的话就重复上面的打印和入栈操作,直到栈为空。
实现代码如下:

private static void preOrderNoR(TreeNode root){
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();

        while (!stack.empty() || cur!=null){
            //优先走左边
            while (cur!=null){
                //第一次遇到cur这个节点的位置
                System.out.print(cur.val);
                stack.push(cur);
                cur = cur.left;
            }
            //向左走到头了需要回溯
            //从栈里取出节点进行回溯
            //目前栈里的所有节点的右子树都没有进行遍历
            TreeNode top = stack.pop();
            cur = top.right;
        }
    }

中序遍历

思路:
中序遍历是先遍历左子树,然后根节点,最后遍历右子树。和上面操作一样的是需要借助栈来完成。
cur先指向根节点,只要cur不为空,就先入栈,然后一直向左走,走到头之后将栈顶元素出栈,打印栈顶元素的值并且将cur指向栈顶元素的右子树,为空的话就出栈下一个栈顶元素并打印,cur再指向刚刚出掉的那个节点的右子树,不为空的话就重复上面入栈的操作,直到栈为空。
在这里插入图片描述
还是用这棵树来说,从根节点一直向左走,4的左子树为空,将4出栈并打印,然后去遍历4的右子树,也为空,所以接着将下一个栈顶元素2出栈并打印,遍历2的右子树,不为空,将5入栈。
在这里插入图片描述
判断5的左子树为空,所以将栈顶元素5出栈并打印,5的右子树也为空,继续将栈顶元素1出栈并打印,遍历1的右子树,不为空,所以3入栈,3的左子树也不为空,6入栈,然后重复上面的操作就可以得到中序遍历的结果。
在这里插入图片描述
具体实现代码如下:

private static void inOrderNoR(TreeNode root){
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();

        while (!stack.empty() || cur!=null){
            //优先走左边
            while (cur!=null){
                //第一次遇到cur这个节点的位置
                stack.push(cur);
                cur = cur.left;
            }
            //向左走到头了需要回溯
            //从栈里取出节点进行回溯
            //目前栈里的所有节点的右子树都没有进行遍历
            TreeNode top = stack.pop();
            //top取出的节点,是第二次遇到该节点
            System.out.print(top.val);
            cur = top.right;
        }
    }

后序遍历

思路:
后序遍历的非递归实现相对复杂,需要考虑的情况比较多。先遍历左子树,再遍历右子树,最后打印根节点。
首先我们还是定义一个栈和一个引用cur指向根节点,再定义一个last引用,用来保存上一次被完整后序遍历过的树的根节点。
将cur引用走到左子树的尽头,然后查看栈顶元素,只要它的右子树不为空,就将cur引用指向它的右子树,如果cur不为空就重复入栈的操作。
而如果栈顶元素的右子树为空或者是已经被遍历过的根节点,就直接将这个栈顶元素打印并出栈,更改last引用的指向,直到栈为空。
用具体例子来说就是:
和中序遍历一样,cur引用只要不为空就入栈并且一直向左走。
在这里插入图片描述
走到头之后查看栈顶元素为4,4的右子树为空,所以打印4并且将4出栈,last引用指向4,表示4是之前已经遍历过的根节点。
虽然现在cur为空,但是当前栈并不为空,所以接着查看栈顶元素2,2的右子树不为空,也不是上次已经遍历过的根节点,所以要去遍历2的右子树。
在这里插入图片描述
2的右子树为5,所以要进行入栈操作,5的左子树为空,右子树也为空,所以将5打印并出栈,更改last引用的指向。
在这里插入图片描述
接着查看栈顶元素为2,2的右子树不为空,但是等于上次已经遍历过的根节点,也就是last引用指向的节点,所以直接打印并出栈,再次更改last引用的指向。
在这里插入图片描述
一直重复上述步骤,直到栈为空,就可以得到后序遍历的结果,代码如下:

private static void postOrderNoR(TreeNode root){
        TreeNode cur = root;
        TreeNode last = null;       //上一次被完整后序遍历过的树的根节点
        Stack<TreeNode> stack = new Stack<>();

        while (!stack.empty() || cur!=null){
            //优先走左边
            while (cur!=null){
                //第一次遇到cur这个节点的位置
                stack.push(cur);
                cur = cur.left;
            }
            //向左走到头了需要回溯
            //从栈里取出节点进行回溯
            //目前栈里的所有节点的右子树都没有进行遍历
            TreeNode top = stack.peek();
            if (top.right==null){
                System.out.print(top.val);
                stack.pop();
                last = top;
            }else if (top.right==last){
                System.out.print(top.val);
                stack.pop();
                last = top;
            }else {
                cur = top.right;
            }
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值