二叉树遍历

题目链接

leetcode-144:前序遍历
leetcode-94:中序遍历
leetcode-145:后序遍历
leetcode-102:层序遍历

二叉树的深度遍历

递归遍历

  1. 前序遍历
class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        traverse(root);
        return res;
    }
    void traverse(TreeNode root) {
        if(root == null) return;
        res.add(root.val);
        traverse(root.left);
        traverse(root.right);
    }
}
  1. 中序遍历
class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        traverse(root);
        return res;
    }
    void traverse(TreeNode root) {
        if(root == null) return;
        traverse(root.left);
        res.add(root.val);
        traverse(root.right);
    }
}
  1. 后序遍历
class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        traverse(root);
        return res;
    }
    void traverse(TreeNode root) {
        if(root == null) return;
        traverse(root.left);
        traverse(root.right);
        res.add(root.val);
    }
}
  1. 总结
    (1)、迭代切勿纠结于细节,而是应该追求逻辑的自洽
    (2)、二叉树的模板框架:
    void traverse(TreeNode root) {
        if(root == null) return;//判断“归”的条件
        //前序代码位置
        traverse(root.left);
        //中序代码位置
        traverse(root.right);
        //后序代码位置
    }

(3)、递归函数我粗略的认为就是循环,类似于数组的遍历,只不过这个是二叉树的遍历,以下代码就是循环的框架,粗略认为只要traverse(或者其他名词)同时出现三次就算是完成了循环,然后相对应的数组循环有i<nums.length的条件,那么递归也应该有终止条件,即if(root == null) return,数组中也有循环主体,即是你要做的事情,相应的递归函数中,前序、中序、或者后序代码位置就是你的循环主体。

    void traverse(TreeNode root) {
        traverse(root.left);
        traverse(root.right);
    }
  1. 递归的三个部分:
    (1)、确定函数的返回值以及函数的定义
    (2)、确定终止条件,做到有递有归
    (3)、确定单层递归的逻辑,即假设你自己站在节点上,你需要做什么,你需要知道什么,将这些代码写到前序、中序、或者后序代码位置,以此解题。

迭代遍历

  1. 前序遍历
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root == null) return new LinkedList<Integer>();
        LinkedList<TreeNode> stack = new LinkedList<>();
        LinkedList<Integer> res = new LinkedList<>();
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode curNode = stack.pop();
            res.add(curNode.val);//前序代码位置
            if(curNode.right != null) {
                stack.push(curNode.right);//遍历左子树
            }
            if(curNode.left != null) {
                stack.push(curNode.left);//遍历右子树
            }
        }
        return res;
    }
}
  1. 中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root == null) return new LinkedList<Integer>();
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode curNode = root;
        LinkedList<Integer> res = new LinkedList<>();
        while(curNode != null || !stack.isEmpty()) {
            while(curNode != null) {
                stack.push(curNode);
                curNode = curNode.left;//遍历左子树
            }
            curNode = stack.peek();
            res.add(curNode.val);//中序位置代码
            curNode = curNode.right;//遍历右子树
            stack.pop();
        }
        return res;
    }
}
  1. 后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root == null) return new LinkedList<Integer>();
        List<Integer> res = new LinkedList<>();//存出二叉树节点
        LinkedList<TreeNode> stack = new LinkedList<>();//维护一个栈
        TreeNode curNode = root;//维护一个当前节点
        TreeNode visitNode = root;//维护一个已经访问节点
        while(curNode != null || !stack.isEmpty()) { //栈不为空或者当前节点不是叶子结点
            while(curNode != null) {
                stack.push(curNode);//入栈
                curNode = curNode.left;//遍历左子树
            }
            curNode = stack.peek();
            if(curNode.right != null && curNode.right != visitNode) {
                curNode = curNode.right;//遍历右子树
            } else {
                res.add(curNode.val);//后序代码位置
                visitNode = curNode;//当前节点设为已访问节点
                curNode = null;//当前节点设为空,防止再次访问
                stack.pop();//出栈
            }
        }
        return res;
    }
}
  1. 总结
    (1)、上述三种迭代二叉树的方式均需要维护一个栈stack,这是因为递归正是栈的体现。
    (2)、前序迭代需要stack,中序迭代需要stackcurNode,前序迭代需要stackcurNodevisitNode
    (3)、代码书写时,需要注意stack<TreeNode>,以及if(root == null) return new LinkedList<Integer>()不要写错。
    (4)、前序遍历的代码是先右子树,再左子树,中序和后序都是先左子树再右子树。

二叉树的广度遍历

层序遍历

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if(root == null) return result;
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            int n = queue.size();//当前队列的大小
            List<Integer> list = new ArrayList<>();
            for(int i=0; i<n; i++) {
                TreeNode curNode = queue.poll();
                list.add(curNode.val);
                if(curNode.left != null) {
                    queue.offer(curNode.left);//遍历左子树
                }
                if(curNode.right != null) {
                    queue.offer(curNode.right);//遍历右子树
                }
            }
            result.add(list);
        }
        return result;
    }
}
  1. 总结
    (1)、层序遍历和前序遍历很像,代码几乎一样,前者使用单向队列,先遍历左子树,后遍历右子树;后者使用栈,先遍历右子树,后遍历左子树。
    (2)、层序遍历在循环体内需要维护一个队列的大小,也可以不维护,视情况而定。

环环无敌大可爱😄

posted @ 2022-04-17 00:57  盐小果  阅读(22)  评论(0编辑  收藏  举报