二叉树三种遍历

前序遍历和中序遍历

通过指针指向树的各个节点,不为空则放入栈,等待后续遍历,指针每次遍历左边节点,再遍历右边节点。

相当于

      1
   2      3
4    5  6    7

执行

// 结点栈:
null
// 第一次弹出,加入到结点栈
1
// 加入到结果集
1
// p 指向左结点
p = 2

// 以此类推

// 结点栈
4 5 2 1
// 结果集
1 2 4 5
// p 指向空
这时候,弹出4
p 指向5
// 以此遍历
public List<Integer> preorderTraversal(TreeNode root) {
        Deque<TreeNode> stack = new ArrayDeque<>();
        List<Integer> resList = new ArrayList<>();

        TreeNode p = root;

        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p);
                resList.add(p.val);
                p = p.left;
            } else {
                TreeNode tmp = stack.pop();
                p = tmp.right;
            }
        }

        return resList;
    }

中序遍历

public List<Integer> preorderTraversal(TreeNode root) {
        Deque<TreeNode> stack = new ArrayDeque<>();
        List<Integer> resList = new ArrayList<>();

        TreeNode p = root;

        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p);
                p = p.left;
            } else {
                TreeNode tmp = stack.pop();
                resList.add(tmp.val);

                p = tmp.right;
            }
        }

        return resList;
    }

后序遍历

我个人理解的有两种方法

  1. 层次遍历(力扣官方题解)

    每次把栈首元素弹出放入结果集,按元素的右左孩子的顺序压入栈,之后再弹出。

    比如

          1
       2      3
    4    5  6    7
    

    那么我们第一次压栈的顺序是

    // 开始时结点栈顺序
    1
    
    // 结点栈顺序(弹出1加入到结果)
    3 2
    // 结果栈的顺序
    1
    
    // 第二次结点栈顺序(弹出3加入到结果)
    7 6 2
    // 第二次结果栈顺序
    3 1
    
    // 以此类推。。。
    // 右结点遍历完的结点栈
    2
    // 结果栈
    6 7 3 1
    // 再类推就可以得到结果
    
    public List<Integer> postorderTraversal(TreeNode root) {
            if (root == null) {
                return new ArrayList<>(0);
            }
    
            Deque<TreeNode> stack = new ArrayDeque<>();
            Deque<Integer> deque = new LinkedList<>();
            stack.push(root);
    
            TreeNode p = null;
    
            while (!stack.isEmpty()) {
                p = stack.pop();
                deque.push(p.val);
    
                if (p.left != null) {
                    stack.push(p.left);
                }
    
                if (p.right != null) {
                    stack.push(p.right);
                }
            }
    
            return (List<Integer>) deque;
        }
    
  2. 压栈模仿递归,每次压右再压左,这样左边遍历完就可以直接遍历右边了。直到走到空,例如:

          1
       2      3
    4    5  6    7
    

    栈中是这样的

    4 5 2 3 1
    

    这个时候,直接把4加入到结果集就可以,然后再看一下下一个5,4和5没有关系,所以直接遍历5。

    接下来是这样的,由于5左右都没有结点,所以到了需要弹出5的时候了,这个时候,先弹出5,加到结果集,然后再取出第一个2,看5和2的关系,是父子关系,证明2已经遍历过了,直接把2弹出就行了。

    5 2 3 1
    

    最后结果可能是这样的

    7 3 1
    

    这个时候就需要弹出一次,再看下一个是不是也是父子关系,相当于连续弹出三次,完毕。

    public List<Integer> postorderTraversal2(TreeNode root) {
            if (root == null) {
                return new ArrayList<>();
            }
    
            Deque<TreeNode> stack = new ArrayDeque<>();
            List<Integer> resList = new ArrayList<>();
            stack.push(root);
    
            TreeNode p = root;
    
            while (!stack.isEmpty()) {
                if (p != null) {
                    if (p.right != null)
                        stack.push(p.right);
                    if (p.left != null)
                        stack.push(p.left);
    
                    p = p.left != null ?
                            p.left :
                            p.right;
                } else {
                    TreeNode tmp = stack.pop();
                    resList.add(tmp.val);
    
                    TreeNode pre = stack.peek();
                    while (isChildren(tmp, pre)) {
                        resList.add(pre.val);
                        tmp = stack.pop();
    
                        pre = stack.peek();
                    }
    
                    p = pre;
                }
            }
    
            return resList;
        }
    
        private boolean isChildren(TreeNode c, TreeNode p) {
            if (c == null || p == null) {
                return false;
            }
    
            return p.left == c || p.right == c;
        }
    

猜你喜欢

转载自blog.csdn.net/qq_42254247/article/details/107891920