数据结构&算法篇(1)--二叉树的构建与遍历2-非递归遍历

二叉树的非递归遍历
可以先看下上篇文章:二叉树的括号表示法构建&递归遍历- https://blog.csdn.net/qq_25179481/article/details/119062547

1)、先序遍历

/**
 *  非递归的二叉树先序遍历
 * @return
 */
public String stackTraversPreStr()
{
    StringBuffer buffer = new StringBuffer();
    stackTraversPre(parent,buffer);
    return buffer.toString();
}

/**
 * 非递归的话主要是使用栈先进后出的特性。
 *
 * 例如当前前序遍历,先是父节点,在左子树,然后右子树。
 * 这样对应的操作,就是先出栈打印父节点,然后右子树入栈,再左子树入栈。
 * 由于是后进先出,这样就会下次while循环的时候是先左子树出栈。
 * 以它为父节点,打印它,再将其右子树入栈,再左子树。
 *
 * 这样就会是先
 *                                  父节点    (左右入栈C、B)
 *                 -》B左子树出栈   (将其左子树入栈D)
 *              -》D左子树出栈        (将其右子树G入栈)
 *                      -》G右子树  (出栈打印)
 *                                               -》 C右子树出栈      (将F、E入栈)
 *                                           -》 左子树
 *                                                      -》右子树
 *                    这样打印
 *
 * @param node
 * @param buffer
 * @return
 */
public String stackTraversPre(Node node,StringBuffer buffer)
{
    if (Objects.isNull(node))
    {
        return "";
    }
    Stack<Node> nodeStack = new Stack<>();
    nodeStack.push(parent);
    while (!nodeStack.empty())
    {
        Node popNode = nodeStack.pop();
        buffer.append(popNode.value);
        if (Objects.nonNull(popNode.right))
        {
            nodeStack.push(popNode.right);
        }
        if (Objects.nonNull(popNode.left))
        {
            nodeStack.push(popNode.left);
        }
    }
    return buffer.toString();
}

2)、中序遍历

/**
 * 非递归的中序遍历 (左子树、中、右子树)
 *
 *  要中序遍历,由于是先左子树(要注意是左子树,不是单一的左节点)。
 *  由于是树,可能左子树节点还有左子树,所以会先遍历到
 * @return
 */
public String stackTraversInStr()
{
    StringBuffer buffer = new StringBuffer();
    stackTraversIn(parent,buffer);
    return buffer.toString();
}

/**
 * 非递归的中序遍历 (左子树、根节点、右子树)
 *
 *  要中序遍历,由于是先左子树(要注意是左子树,不是单一的左节点)。
 *  由于是树,可能左子树节点还有左子树。
 *  ** 所以最先需要做的就是先从根节点遍历到到整颗树的最下面一层的左节点(如果存在)。
 *      在这个过程中,就形成了一个调用链,也就是链路中间的节点是下一个节点的父节点,同时它一个它的父节点的左节点
 *  **
 *
 *  所以在出栈的时候最先开始的是最下面一层的左节点。
 *  再出栈就是父节点,出栈后我们就需要去处理其的右节点了,所以就是将右节点入栈
 *  再下一次将右节点出栈,这样就完成了完整的子树(左节点、父节点、右节点)的遍历。同时这三个都出栈了。
 *  接下来就是以前面的两个左右节点的父节点(标记为A)为左子树的父节点的循环遍历。
 *  在下面的代码中要具体完全理解<code>newNode</code>。要理解当其为<code>null</code>的时候,
 *  这个时候就会直接是到前面标记的A节点的右子树的遍历了(同时又会是再次整个过程了)
 *
 * @return
 */
public void stackTraversIn(Node node,StringBuffer buffer)
{
    if (Objects.isNull(node))
    {
        return;
    }
    Stack<Node> nodeStack = new Stack<>();
    nodeStack.push(node);
    Node newNode = node;
    while (!nodeStack.empty())
    {
        while (newNode != null)
        {
            if (Objects.nonNull(newNode.left)) {
                nodeStack.push(newNode.left);
            }
            newNode = newNode.left;
        }
        Node popNode = nodeStack.pop();
        buffer.append(popNode.value);
        newNode = popNode.right;
        if (Objects.nonNull(newNode))
        {
            nodeStack.push(newNode);
        }
    }
}

3)、后序遍历

/**
 * 非递归的后序遍历
 * @return
 */
public String stackTraversAfterStr()
{
    StringBuffer buffer = new StringBuffer();
    stackTraversAfter(parent,buffer);
    return buffer.toString();
}

/**
 * 后序遍历(先左子树,右子树,根节点)
 * 后序遍历与前面的中序遍历类似,都是先将所有的左节点入栈
 * 但后序遍历你出栈一个节点,它可能是有三种情况:
 *      1、右节点为null,表示就它一个了,它没有子树,可以打印了,
 *      2、或者当前栈顶的节点等于上次遍历的节点。表示其已经完成了左右节点的遍历,可以打印
 *      3、最后就是上面都不满足,就表示要将右节点入栈,
 *          先处理这个右节点,处理之后,就可以达到2的目标,来打印这个父节点了
 *
 * @param node
 * @param buffer
 */
public void stackTraversAfter(Node node,StringBuffer buffer)
{
    Stack<Node> nodeStack = new Stack<>();
    nodeStack.push(node);
    Node happenNode = node;
    Node newNode = node;
    while (!nodeStack.isEmpty())
    {
       while (Objects.nonNull(newNode))
       {
           if (Objects.nonNull(newNode.left)) {
               nodeStack.push(newNode.left);
           }
           newNode = newNode.left;
       }
        Node popNode = nodeStack.peek();
        if (Objects.isNull(popNode.right) ||
                (Objects.nonNull(popNode.right) && happenNode.value.equals(popNode.right.value)))
       {
           buffer.append(popNode.value);
           happenNode = popNode;
           nodeStack.pop();
       }
       else
       {
           nodeStack.push(popNode.right);
           newNode = popNode.right;
       }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值