算法 - 二叉树的10种遍历方法,你都会了么?( 二 )

在上一篇文章(二叉树的遍历( 一 ))中,我们通过思考函数入栈出栈的过程,理解了递归遍历二叉树的原理,下面我们来理解非递归的写法。

在递归遍历中,我们发现,程序首先把根节点的左’子孙’依次入栈,所以我们可以有如下代码:

public void traverse1(TreeNode root){
    if(root == null) return;
    Stack<TreeNode> stack = new Stack<>();
    TreeNode nodeee = root;
    while(node != null){
        //visit 先序         stack.push(node);
        node = node.left;
    }

然后,如果栈不为空,依次出栈,看其是否有右子节点,如果有右节点,执行上一步操作:

  while (stack.size() > 0) {
        node = stack.pop();
        //visit 中序         if (node.right != null) {
            node = node.right;
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
        }
    }
}

那么,先序遍历的visit点,就在stack.push()之前;中序遍历的visit点,就在stack.pop() 之后。

上面这两段代码可以优化为下面一个循环:

public static void traverse2(TreeNode root){
        if(root == null) return;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while(!(node==null && stack.empty())){
            while(node != null){
                //visit 先序                 stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            //visit 中序             node = node.right;
        }
    }

这样就实现了非递归的先序遍历和中序遍历。

还有另一种方式实现非递归的先序遍历,用了深度优先搜索(DFS)的思想,其实,二叉树的先序遍历,中序遍历,后序遍历,都是深度优先搜索。

深度优先搜索:

首先,把根节点入栈。 ①

如果栈不为空,弹出栈顶元素。 ②

把该元素的子节点入栈。 ③

循环②,③,直到栈为空。④

那么,我们只要保证右节点先于左入栈,就能实现”根->左->右“的先序遍历。

代码如下:

  public static void traverse3(TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.empty()){
            TreeNode node = stack.pop();
            //visit 先序             if(node.right != null){
                stack.push(node.right);
            }
            if(node.left != null) {
                stack.push(node.left);
            }
        }
    }

从这个思想出发,我们可以很简单的实现另一种遍历:”根->右->左“遍历。

虽然这种遍历没有名字,但是他是后序遍历的反序。所以我们可以利用两个栈,利用栈的LIFO特点,来实现后续遍历。

代码如下:

  public static void traverse4(TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        Stack<TreeNode> result = new Stack<>();
        stack.push(root);
        while(!stack.empty()){
            TreeNode node = stack.pop();
            //visit 根->右->左             result.push(node);
            if(node.left != null) {
                stack.push(node.left);
            }
            if(node.right != null){
                stack.push(node.right);
            }
        }
       while(!result.empty()){
           node = result.pop();
           //visit 后序        }
    }

那么,怎么用一个栈来实现后序遍历呢?

下面的文章会讲到。

为什么我们模拟程序栈的时候,没有后续遍历的visit点呢?

这主要是因为后序遍历是非尾递归的,深层的原因,之后可能会讲到。

咳咳,欢迎关注,欢迎点赞,欢迎评论哦~~

    原文作者:李井瑞
    原文地址: https://zhuanlan.zhihu.com/p/34574662
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞