二叉树 III —— 二叉树非递归遍历(前、中、后序)

本文详细介绍了如何将二叉树的前序、中序和后序递归遍历转换为非递归遍历。通过借助栈的数据结构,分别展示了前序非递归遍历的两种思路,中序非递归遍历的实现以及后序非递归遍历的步骤。代码实现清晰地解释了每个遍历过程。
摘要由CSDN通过智能技术生成

在上一篇博客中我们介绍了二叉树的前中后序递归遍历,本篇博客我们来看看如何将递归遍历变为非递归遍历。博客链接:二叉树存储、递归遍历(前、中、后序).

前序非递归遍历

对于前序遍历我们知道它的访问顺序是根节点---->根节点的左子树---->根节点的右子树。

对于递归改为非递归,一般有两种思路:

  • 借助栈实现
  • 通过for循环实现

因此,我们的递归遍历就采用借助栈来实现。并且对于前序非递归遍历我们有两种思路。

思路一:

我们先思考一下,前序遍历是先访问根节点,然后依次访问根节点的左右子树。对于栈,栈的特点是先进后出,我们如何将两者结合起来呢?

先进后出?对于后出(最后访问的)节点我们首先需要把他压入栈中,所以,

  • 对于根节点,它是一开始就被访问,直接入栈,每次直接访问(打印、存储等操作);

  • 在前序遍历中,右子树是最后访问的,那么就需要先于左子树入栈

  • 对于左子树,他是第二顺序被访问,那么它就需要在右子树的后面进栈

我们总结一下,先序非递归的遍历实现步骤如下:

  1. 空树—>直接返回
  2. 树不为空:将根节点入栈,循环进行以下操作
    • 取栈顶元素:cur = stack.peek()
    • 遍历该元素:也就是访问该根节点
    • 删除栈顶元素
    • 如果cur的右子树存在,将右子树入栈
    • 如果cur的左子树存在,将左子树入栈

代码实现:

//前序非递归遍历
public void preOrderNor()
{
     if(root==null)
     {
         return ;
     }
     Stack<BTNode> s=new Stack<>();
     s.push(root);
     while(!s.isEmpty())
     {
         BTNode cur=s.peek();
         System.out.print(cur.val+" ");
         s.pop();
         if(cur.right!=null)
         {
             s.push(cur.right);
         }
         if(cur.left!=null)
         {
             s.push(cur.left);
         }
     }
 }

思路二:

以没有被遍历的节点为一颗新的子树,顺着一条路径往左走,如果当前节点有右孩子将其右孩子保存在栈中,没有则向左走(遍历该节点)

先序非递归的遍历实现步骤如下:

  1. 空树—>直接返回
  2. 树不为空:将根节点入栈,循环进行以下操作(循环条件:栈不为空):
    • 取栈顶元素: cur = stack.peek()
    • 让该元素出栈,循环进行以下操作(循环条件:cur!=null,即:让当前路径一直向左走):
      • 遍历当前元素(cur)
      • 如果cur的右子树存在,将右子树入栈
      • 如果cur的右子树不存在,一直向左走( cur=cur.left )

代码实现:

public void preOrderNor2()
{
    if(root==null)
    {
        return ;
    }
    Stack<BTNode> s=new Stack<>();
    s.push(root);
    while(!s.isEmpty())
    {
        BTNode cur=s.peek();
        s.pop();
        //cur!=null,也就是顺着一条路径一直向左
        while(null!=cur)
        {
            //顺着cur左侧这条路路径,遍历左子树,保存右子树
            System.out.print(cur.val+" ");
            if(cur.right!=null)
            {
                s.push(cur.right);
            }
            cur=cur.left;
        }
    }
}

中序非递归遍历

中序遍历非递归的两种方式见我的另一篇博客,里边有详细的分析以及代码。
博客链接:Leetcode94-二叉树中序非递归遍历.

后序非递归遍历

在看了二叉树的中序非递归遍历后,其实后序非递归遍历和中序非递归遍历的唯一区别就是访问(打印)根节点的先后顺序不同。

在这里插入图片描述
具体步骤如下:

  1. 先找以root为根的左子树最左下的节点,并保存所经路径的所有节点-----》保存到栈里。

    • 以上图中的二叉树为例,最终会停留在3这个节点。 可以认为3的左子树已经遍历结束,接下来只能遍历3的右子树
    • 循环条件:while(cur!=nll || !s.empty() ),
  2. 获取栈顶元素----->获取3的右子树的根节点,拿到栈顶的元素(也就是3),然后遍历3的右子树

    • 右子树为null:遍历3这个节点,并且将该节点出栈
    • 右子树非空:将3的右子树当成新的树进行遍历,这个时候不能打印栈顶元素(值为3)否则就变成中序非递归
  3. 最后才打印栈顶元素(没有右孩子)

代码实现:

 public void lastOrderNor()
    {
        System.out.println("非递归后续遍历:");

        if(root==null)
        {
            return;
        }

        //1>先找以root为根的左子树最左下的节点,并保存所经路径的所有节点---》保存到栈里。
        Stack<BTNode> s =new Stack<>();
        BTNode cur= root ;

        BTNode prev=null;//标记刚刚遍历过的节点
        while (!s.empty()  ||  cur!=null)
        {
        //先将左子树依次入栈
            while (cur!=null)
            {
                s.push(cur);
                cur=cur.left;
            }
            //2.获取栈顶元素
            BTNode node=s.peek();

            //node右孩子为空----》就可以遍历根节点
            //node的右孩子已经遍历完成-----》就可以遍历根节点
            if(node.right==null &&  node.right==prev)//没右孩子
            {
                //没有右孩子:打印该节点,并出栈
                System.out.print(node.val+" ");
                prev=node;//将访问过的右节点标记起来,来避免循环压栈
                s.pop();

            }else {//有右孩子
                cur=node.right;
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值