Binary Tree Traversal I Depth First Search

Tree Traversal

Part I: DFS Recursion实现

  • 注意这颗特别的树

DFS遍历的本质(核心要点)

注意走三次,pre,in,post,第几次回就是对应的,i.e.

DFS遍历的本质(核心要点)

  • 一笔画走完每一个分支,每个其实会经过三次,

    • 第一次经过,就是DFS preOrder

      • 也是从你的parent call的时候,从上到下的过程

    • 第二次经过,就是DFS inOrder

      • 从你的左子树回来的时候经过你的过程,从下到上的过程

    • 第三次经过,就是DFS postOrder

      • 从你的右子树回来的时候最后一次经过你的时候(马上下一站该会parent):从下到上的过程

Part II: DFS Iteration 实现

版本1(可以给preOrder & inOrder)

// Some code

public void generalDFS(Tree){
    TreeNode cur = root;
    Deque<TreeNode> stack = new ArrayDeque<>();
    while(cur != null || !stack.isEmpty()) {
        if (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }else {
            cur = stack.pop();
            cur = cur.right;
        }
    }
}
  • 经过这个概念,第几次经过,第一次,第二次都好,但是第三次不行

  • 我们总是在第二次经过的时候就给他pop出来,然后我们就没有机会第三次cur赋予为这个node

版本2(错误)

// Some code
public void generalDFS(Tree){
    TreeNode cur = root;
    Deque<TreeNode> stack = new ArrayDeque<>();
    while(cur != null || !stack.isEmpty()) {
        if (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }else {
            cur = stack.peek();
            cur = cur.right;
        }
    }
}
  • 问题更大,不是不好表达,根本就是错误,这个while循环可能进不去么?单反是有一个点进去了,全程没有pop

  • 第一次,第二次都没有问题,第三次本来就应该是pop出来,第三次也peek了,第四次,第五次。。。。

  • 根本问题在于:所以第二次和第三次经过的本质区别是啥?

    • 第二次和第三次经过这个点他们的本质区别在哪?方向不同?第二次经过他是从左子树回来,而第三次经过它是从右子树回来

    • 所以可以用prevNode,知道上一次访问的(visit)的node如果是左子树的根节点,那我一定是第二次经过你啊我是从你左边回来的,如果我上一次访问的(visit)的node如果是右子树的根节点,那我一定是第三次是经过你了因为我是从你的右边回来的

版本3 加个lastVisited(可以给postOrder)

  • 如果我只是想写post order,其实我不需要知道我是第几次经过这个点,而我更需要知道的是我从哪个点访问完以后才来经过当前点的,看从左还是从右回来就可以了

// Some code


public void generalDFS(TreeNode root) {
    TreeNode cur = root;
    Deque<MyTreeNode> stack = new ArrayDeuque<>();
    List<Integer> result = new ArrayList<>();
    TreeNode lastVisited = null; //上一次postOrder访问的点是谁呢?
    while (cur != null || !stack.isEmpty()) {
        if (cur != null) {
            cur.count++;
            
            stack.push(cur);
            cur = cur.left;
        }
        else {
            TreeNode peekNode = stack.peek();
            if (peekNode.right != null) && lastVisited != peekNode.right) {
                //有右边,而且你不是从右边回来,而且你还在else分支里,第二次经过被
                cur = peekNode.right;
            }else {
                // 要么你没右子树,要么你虽然右子树但是你刚从那边回来,访问完右子树
                result.add(peekNode.val);
                lastVisited = stack.pop();
            }     
        }
    }
    return result;
}

版本4 自己数啥时候经过

count:就是第几次经过

// Some code
class MyTreeNode {
    TreeNode node;
    int count;
    public MyTreeNode(TreeNode root) {
        this.node = root;
    }
}

public void generalDFS(MyTreeNode root) {
    MyTreeNode cur = new MyTreeNode(root);
    Deque<MyTreeNode> stack = new ArrayDeuque<>();
    List<Integer> result = new ArrayList<>();
    while (cur != null || !stack.isEmpty()) {
        if (cur != null) {
            cur.count++;
            //result.add(cur);
            stack.push(cur);
            cur = new MyTreeNode(cur.node.left);
        }
        else {
            MyTreeNode peekNode = stack.peek();
            peekNode.count++;
            if (peekNode.count == 3) {
                // this is the last bus
                //result.add(peekNode.node.val);
                stack.pop();
            }
            if (peekNode.count == 2) {
                //result.add(peekNode.node.val);
                if (peekNode.node.right != null) {
                    cur = new MyTreeNode(peekNode.node.right);
                }
            }
        }
    }
}

Last updated