• 二叉树的基本知识



    title: 二叉树的基本知识
    date: 2022-06-12 15:37:23
    tags:

    • 二叉树
    • 算法

    二叉树的四种遍历方式

    不要较真,其实也可以分为两种:广度优先(层级)和深度优先(前序、中序、后序)

    基本概念不再赘述。复杂度:设二叉树中元素数目为n。这四种遍历算法的空间复杂性均为O (n),时间复杂性为O(n)。

    二叉树数据结构

    class TreeNode {
            int val;
            TreeNode left;
            TreeNode right;
            TreeNode() {}
            TreeNode(int val) { this.val = val; }
            TreeNode(int val, TreeNode left, TreeNode right) {
                this.val = val;
                this.left = left;
                this.right = right;
            }
        }
    
          1
         / \
        2   5
       / \     
      3   4   
    

    前序遍历

    遍历顺序:根节点-> 左节点-> 右节点

    代码实现:

    /**
         * 前序遍历  根 -> 左 -> 右
         */
        public void preOrder(TreeNode tree){
            if (tree == null){
                return;
            }
            System.out.print(tree.val);
            preOrder(tree.left);
            preOrder(tree.right);
        }
    

    非递归方式

    //java 中使用 Deque, Stack已经弃用。
        //Deque 的使用用法:push、pop。
        public void perOrderIter(TreeNode root){
            if (root == null){
                return;
            }
            Deque<TreeNode> stack = new ArrayDeque<>();
            StringBuilder result = new StringBuilder();
            stack.push(root);
            while(!stack.isEmpty()){
                TreeNode treeNode = stack.pop();
                result.append(treeNode.val);
                if (treeNode.right != null){
                    stack.push(treeNode.right);
                }
                if (treeNode.left != null){
                    stack.push(treeNode.left);
                }
            }
            System.out.println(result.toString());
        }
    

    中序遍历

    遍历顺序:左节点-> 根节点-> 右节点

    代码实现

    /**
     * 中序遍历  左 -> 根 -> 右
     * 结果:32415
     */
    public void midOrder(TreeNode tree){
        if (tree == null){
            return;
        }
        midOrder(tree.left);
        System.out.print(tree.val);
        midOrder(tree.right);
    }
    
    /**
         * 迭代式中序遍历  左 -> 根 -> 右
         * 这个比较难,重点关注一下。
         */
        public void minOrderIter(TreeNode root){
            if (root == null){
                return;
            }
            Deque<TreeNode> stack = new ArrayDeque<>();
            StringBuilder result = new StringBuilder();
            while(root != null || !stack.isEmpty()){
    
                //此处的目的是放入将根节点放入,然后将根节点的左节点压在根节点上面。
                while (root != null){
                    stack.push(root);
                    root = root.left;
                }
                //调出栈
                root = stack.pop();
                result.append(root.val);
                root = root.right;
            }
            System.out.println(result.toString());
        }
    

    后序遍历

    遍历顺序:左节点-> 右节点-> 根节点

    /**
         * 后序遍历  左 -> 右 -> 根
         * 结果:34251
         */
        public void postOrder(TreeNode tree){
            if (tree == null){
                return;
            }
            postOrder(tree.left);
            postOrder(tree.right);
            System.out.print(tree.val);
        }
    
    /**
         * 迭代式后序遍历
         * 后序遍历更复杂!!!!
         * 先遍历左节点 -> 右节点 -> 根节点
         *      1
         *      / \
         *     2   5
         *    / \
         *   3   4
         *      / \
         *     7   8
         */
        public void postOrderIter(TreeNode root){
            if (root == null){
                return;
            }
            Deque<TreeNode> stack = new ArrayDeque<>();
            StringBuilder result = new StringBuilder();
            TreeNode pre = null; //记录前置节点
            while(root != null || !stack.isEmpty()){
                //把所有的左子树节点都放入栈中
                while(root != null){
                    stack.push(root);
                    root = root.left;
                }
    
                //找到当前节点
                root = stack.pop();
                //如果当前节点的右节点为空
                //这里为什么会有对pre的判断,是为了避免重复处理。
                //拿例子:当8已经处理完了之后,应该处理4节点,当时发现4也是有右子树的,但是8已经处理过了,通过pre达标,那么8也不用处理。
                if (root.right == null || pre == root.right){
                    result.append(root.val);
                    //设置前置节点
                    pre = root;
                    //置为空的目的是处理栈中堆积的父节点。
                    root = null;
                } else{
                    //右节点非空,说明当前节点这个时候不能够处理,就把当前节点再放回去。
                    stack.push(root);
                    //把当前节点的右节点作为root进行处理。
                    root = root.right;
                }
            }
            System.out.println(result.toString());
        }
    

    层级遍历

    /**
     * 层级遍历
     * 递归的方式
     * 递归需要存储每个的层级 对应的数据都有什么,借助额外的数据结构
     */
    public List<StringBuilder> result = new ArrayList<>();
    
    public void levelOrder(TreeNode root, int level) {
        if (root == null) {
            return;
        }
        //当数组大小等于层级时,初始化该层级需要的存储空间
        if (result.size() == level) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(root.val);
            result.add(level, stringBuilder);
        } else {
            result.get(level).append(root.val);
        }
        levelOrder(root.left, level + 1);
        levelOrder(root.right, level + 1);
    }
    
    /**
     * 迭代式层级遍历
     * 借助额外的数据结构:队列,特性:先进先出
     * queue 的基本用法:add(offer),remove(poll)
     */
    public void levelOrderIter(TreeNode root) {
        if (root == null) {
            return;
        }
        StringBuilder result = new StringBuilder();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode current = queue.poll();
            result.append(current.val);
            if (current.left != null){
                queue.add(current.left);
            }
            if (current.right != null){
                queue.add(current.right);
            }
        }
        System.out.println(result.toString());
    }
    

    额外:

    /**
     * 获取二叉树的最大深度
     */
    public int getMaxDepth(TreeNode root){
        if (root == null){
            return 0;
        }
        return Math.max(getMaxDepth(root.left)+1,getMaxDepth(root.right)+1);
    }
    

    文章作者: 冯廷鑫
    文章链接: http://fengtingxin.github.io/2022/06/12/二叉树的基本知识/

  • 相关阅读:
    个人工作总结02
    个人工作总结01
    第七周学习进度条
    构建之法阅读笔记03
    第六周学习进度条
    团队开发介绍
    最大连通子数组的和
    四则运算-安卓版
    第五周学习进度条
    构建之法阅读笔记02
  • 原文地址:https://www.cnblogs.com/fengtingxin/p/16369406.html
Copyright © 2020-2023  润新知