【代码训练营】day13 二叉树章节-递归与迭代遍历方式 144.二叉树的前序遍历 & 94.二叉树的中序遍历 & 145.二叉树的后序遍历

所用代码 java

二叉树遍历 LeetCode 144(前序) 94(中序) 145(后序) 重点!!!

题目链接:144.二叉树的前序遍历 94.二叉树的中序遍历 145.二叉树的后序遍历

递归遍历

思路

  • 前序:根左右
  • 中序:左根右
  • 后序:左右根

前序遍历:根 => 左 => 右

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    preorder(root, list);
    return list;
}public void preorder(TreeNode root, List<Integer> list){
    if (root == null) {
        return ;
    }
    // 根
    list.add(root.val);
    // 左
    preorder(root.left, list);
    // 右
    preorder(root.right, list);
}

中序遍历: 左 => 根 => 右

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    inorder(root, list);
    return list;
}public void inorder(TreeNode root, List<Integer> list){
    if (root == null) {
        return ;
    }
    // 左
    inorder(root.left, list);
    // 根
    list.add(root.val);
    // 右
    inorder(root.right, list);
}

后序遍历: 左 => 右 => 根

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    postorder(root, list);
    return list;
}public void postorder(TreeNode root, List<Integer> list){
    if (root == null) {
        return ;
    }
    // 左
    postorder(root.left, list);
    // 右
    postorder(root.right, list);
    // 根
    list.add(root.val);
}

迭代遍历

其实java实现递归是用栈,所以我们可以利用栈的特性来完成非递归的遍历

前序遍历:根 => 左 => 右

public List<Integer> preorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()){
        // 每次把压入栈的元素取出来(根)以右左的方式压入,取就是左右
        TreeNode node = stack.pop();
        list.add(node.val);
        // 先加右结点
        if (node.right != null){
            stack.push(node.right);
        }
        if (node.left != null){
            stack.push(node.left);
        }
    }
    return list;
}

后序遍历: 左 => 右 => 根

由于前序是 根左右,然后我们可以在前序的基础上使得输入为 根右左,再把链表反转,就变成了左右根

public List<Integer> postorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()){
        // 每次以左右压出栈,取出时便是 根右左
        TreeNode node = stack.pop();
        list.add(node.val);
        // 先加入左结点
        if (node.left != null){
            stack.push(node.left);
        }
        if (node.right != null){
            stack.push(node.right);
        }
    }
    // 链表反转:根右左 => 左右根
    Collections.reverse(list);
    return list;
}

中序遍历: 左 => 根 => 右

中序遍历和前后不同,因为每次根结点需要记录,但不是第一个输出,所以我们需要一个辅助的指针来记录遍历的位置。当指针为null时,证明该结点的左孩子为null了,就把栈顶元素弹出(若该结点是叶子结点,就是二叉树的左,否则就为中),然后往右搜索(相当于 右),然后按顺序加入list。

public List<Integer> inorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    // 定义一个指针进行辅助位置指向
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()){
        if (cur != null){
            // cur所指的结点不为空就直接加入栈
            stack.push(cur);
            // 然后继续向左搜索( 左 )
            cur = cur.left;
        }else {
            // 为空就弹出栈里面结点( 中 )
            cur = stack.pop();
            // 并加入列表 
            list.add(cur.val);
            // 搜索完左孩子后往右搜索 ( 右 )
            cur = cur.right;
        }
    }return list;
}

二叉树的统一迭代法 (模板)

前序遍历:根 => 左 => 右

public List<Integer> preorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()){
        TreeNode node = stack.peek();
        if (node != null){
            // 先弹出栈顶的结点
            stack.pop();
            // 再以 右左 的顺序加入
            if (node.right != null){
                stack.push(node.right);
            }
            if (node.left != null){
                stack.push(node.left);
            }
            // 再加入 根 结点
            stack.push(node);// 加入根结点后添加一个标识符 null
            stack.push(null);
        }else {
            // 遇到标志符null,证明下一个结点是根结点(叶子结点也可以看成根结点)
            // 先弹出null
            stack.pop();
            // 再把该结点的值加入列表
            int num = stack.pop().val;
            list.add(num);
        }
    }
    return list;
}

中序遍历: 左 => 根 => 右

public List<Integer> inorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()){
        TreeNode node = stack.peek();
        if (node != null){
            // 先弹出栈顶的结点
            stack.pop();
            // 以 右 中 左 的顺序加入
            if (node.right != null){
                stack.push(node.right);
            }
            // 加入 根 结点
            stack.push(node);
            // 加入根结点后添加一个标识符 null
            stack.push(null);if (node.left != null){
                stack.push(node.left);
            }}else {
            // 遇到标志符null,证明下一个结点是根结点(叶子结点也可以看成根结点)
            // 先弹出null
            stack.pop();
            // 再把该结点的值加入列表
            int num = stack.pop().val;
            list.add(num);
        }
    }
    return list;
}

后序遍历: 左 => 右 => 根

public List<Integer> postorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()){
        TreeNode node = stack.peek();
        if (node != null){
            // 先弹出栈顶的结点
            stack.pop();
            // 再以 中 右 左 的顺序加入// 加入 根 结点
            stack.push(node);
            // 加入根结点后添加一个标识符 null
            stack.push(null);
            // 右
            if (node.right != null){
                stack.push(node.right);
            }
            // 左
            if (node.left != null){
                stack.push(node.left);
            }}else {
            // 遇到标志符null,证明下一个结点是根结点(叶子结点也可以看成根结点)
            // 先弹出null
            stack.pop();
            // 再把该结点的值加入列表
            int num = stack.pop().val;
            list.add(num);
        }
    }
    return list;
}

总结模板

public List<Integer> postorderTraversal(TreeNode root) {
    // 迭代法
    List<Integer> list = new ArrayList<>();
    if (root == null){
        return list;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()){
        TreeNode node = stack.peek();
        if (node != null){
            // 先弹出栈顶的结点
            stack.pop();
            // 加入顺序: 若前序(根左右)就 根右左 加入
            
            
            stack.push(node);
            // 加入根结点再加入一个标志符,第一个弹出(因为叶子结点也是根结点,不管左还是右)
            stack.push(null);
            // 加入右节点
            if (node.right != null){
                stack.push(node.right);
            }
            // 加入左节点
            if (node.left != null){
                stack.push(node.left);
            }}else {
            // 遇到标志符null,证明下一个结点是根结点(叶子结点也可以看成根结点)
            // 先弹出null
            stack.pop();
            // 再把该结点的值加入列表
            int num = stack.pop().val;
            list.add(num);
        }
    }
    return list;
}

你可能感兴趣的:(代码训练营,java,算法,开发语言,数据结构)