• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
正在努力成为一个优秀的废物
博客园    首页    新随笔    联系   管理    订阅  订阅
二叉树的前序、中序、后序、层序遍历

二叉树是什么?

任意一个节点的子节点个数小于等于2的树为二叉树。

二叉树遍历分类:

前序遍历:根结点 ---> 左子树 ---> 右子树

中序遍历:左子树---> 根结点 ---> 右子树

后序遍历:左子树 ---> 右子树 ---> 根结点

层次遍历:只需按层次遍历即可

节点数据结构:

  public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) {
            val = x;
        }
  }

前序遍历:

递归方式:

    public void preorderTraversalRecursive(TreeNode node,     List<Integer> result) {
        if (node == null) {
            return;
        }
        result.add(node.val);
        preorderTraversalRecursive(node.left, result);
        preorderTraversalRecursive(node.right, result);
    }

非递归方式

访问节点 -> 入栈 -> 访问左子树 -> 出栈 -> 访问右子树

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                // 先访问再入栈
                result.add(node.val);
                stack.push(node);
                node = node.left;
            } else {
                // 此时栈顶节点左子树已经访问过了,开始访问右子树
                node = stack.pop();
                node = node.right;
            }
        }
        return result;
    }

中序遍历:

递归方式:

    public void inorderTraversalRecursive(TreeNode node, List<Integer> result) {
        /**
         * 递归一定要记得写结束条件然后再处理逻辑
         */
        if (node == null) {
            return;
        }
        inorderTraversalRecursive(node.left, result);
        result.add(node.val);
        inorderTraversalRecursive(node.right, result);
    }

非递归方式:

入栈 -> 访问左子树 -> 出栈 -> 访问根节点 -> 访问右节点

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node);
                node = node.left;
            } else {
                // 此时栈顶节点左子树已经访问完成,可以访问节点本身,然后继续访问右子树
                node = stack.pop();
                result.add(node.val);
                node = node.right;
            }
        }
        return result;
    }

后序遍历:

递归方式:

    public void postorderTraversalRecursive(TreeNode node, List<Integer> result) {
        if ( node == null) {
            return;
        }
        postorderTraversalRecursive(node.left, result);
        postorderTraversalRecursive(node.right, result);
        result.add(node.val);
    }

非递归方式:

中序遍历会在左子树访问完成后将根节点出栈,然后访问根节点后再访问右子树,而后序遍历需要在右子树访问完成后访问根节点,访问完左子树之后根节点不能出栈,因此后序遍历的非递归方式需要为每个节点添加一个变量用来标识该节点的左右子树是否已经被访问,如果左右子树都被访问了才可以出栈。

入栈 -> 访问左子树 -> 将根节点的左右子树是否已经访问设置为true -> 访问右子树 -> 根节点出栈,访问根节点

    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        //postorderTraversalRecursive(root, result);
        Stack<TreeNode> stack = new Stack<>();
        Stack<Boolean> lastVisited = new Stack<>(); // 用来标识左右子树是否都已经访问
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node);
                node = node.left;
                lastVisited.push(false);
            } else {
                node = stack.peek();
                if (false == lastVisited.peek()) {
                    // 右子树还没访问,开始访问右子树
                    lastVisited.pop();
                    lastVisited.push(true);
                    node = node.right;
                } else {
                    // 右子树已经访问
                    result.add(node.val);
                    stack.pop();
                    lastVisited.pop();
                    node = null;
                }
            }
        }
        return result;
    }

层序遍历

在每一层结束后添加一个空节点来标识该层结束

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        queue.offer(null);
        List<Integer> level = new ArrayList<>();
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node == null) {
                result.add(level);
                if (!queue.isEmpty()) {
                    level = new ArrayList<>();
                    queue.offer(null);
                }
                continue;
            }
            level.add(node.val);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        return result;
    }

在遍历每层开始时先获取本层节点个数

    public List<List<Integer>> levelOrder2(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int count = queue.size();
            List<Integer> level = new ArrayList<>();
            while (count > 0) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
                count--;
            }
            result.add(level);
        }
        return result;
    }

 

posted on 2020-04-18 15:34  你算哪根小毛线  阅读(286)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3