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

Posted _微风轻起

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构&算法篇--二叉树的构建与遍历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;
       }
    }
}

以上是关于数据结构&算法篇--二叉树的构建与遍历2-非递归遍历的主要内容,如果未能解决你的问题,请参考以下文章

数据结构&算法篇--二叉树的构建与遍历

数据结构&算法篇--二叉树的构建与遍历

直击算法:Dart 中二叉树的构建与遍历

二叉树构建与遍历-LeetCode 103108109(二叉树的构建,层次遍历)

数据结构与算法第10周作业——二叉树的创建和遍历算法

算法_二叉树遍历篇