当前位置: 首页 > news >正文

二叉树的一些基本操作

目录

前言:

前序遍历

代码实现 

中序遍历

 代码实现

后续遍历

代码实现

二叉树节点的个数

代码实现

获取叶子节点的个数

代码实现

获取第K行节点个数

代码实现

二叉树的最大高度

代码实现

二叉树中查找某个数据

代码实现

层序遍历二叉树

代码实现

根据前序遍历字符串构建一颗二叉树

代码实现

小结:


前言:

😆二叉树是一颗结构非常特殊的树,每个节点的度都是小于等于2且大于等于0。树是用递归来定义的,而递归的核心思想是子问题思路,那么大多数处理树相关问题,也需这样去思考。

前序遍历

顺序:根-->左子树-->右子树

🪖在理解子问题思路时,这张图就相当重要。当遍历完根的时候,递归左子树。左子树又是一颗全新的二叉树(左边黑色框框)。到B这个节点的时候,先访问根节点,然后又去递归左子树。到D这个节点,D作为根,又是一颗全新的二叉树(左边绿色框框),然后去递归D的左右子树,都为空,则返回。这时候说明B的左子树遍历完成(回退),去递归B的右子树。E又作为一颗全新的二叉树,分别递归它的左右子树。当A的左右子树全部递归完成后,这时候前序遍历算完成了。

代码实现 

public void preOrder(TreeNode root) {

        if(root == null) {
            return;
        }
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

注意:写递归代码时把握好递推公式(如何去递归),然后是递归的结束条件。

中序遍历

顺序:左子树-->根-->右子树

🤨思路和前序遍历思路是一致的,只是每个节点访问的时机不同。这里我画一张递归展开图,帮助去理解。

 代码实现

public void inOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

后续遍历

顺序:左子树-->右子树-->根

😆思路也和前面一致,先去递归左子树,然后递归右子树,最后访问根节点。

代码实现

 public void postOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

二叉树节点的个数

😯还是子问题思路,每棵树节点个数都是左子树节点个数 + 右子树节点个数 + 1(根节点)。然后考虑递归结束条件:当初树为空时,返回即可。

注意:在脑海中要能想到这样的递归过程。累加就是在递归回退的过程中。

代码实现

public int size(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return size(root.left) + size(root.right) + 1;
    }

获取叶子节点的个数

🧢同样是子问题思路,左子树叶子节点个数 + 右子树叶子节点个数。考虑递归结束条件:当树为空时,这时候直接返回0。当递归到叶子节点的时候,返回1。(累加过程也是在递归回退的时候)

代码实现

public int getLeafNodeCount(TreeNode root) {
        if(root == null) {
            return 0;
        }
        if(root.right == null && root.left == null) {
            return 1;
        }
        return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
    }

获取第K行节点个数

🎄假设获取第3行节点个数,用K去控制递归的层数。相对于第一行是求第三行节点个数,相对于第二行是求第二行节点个数,相对于第三行是求第一行节点个数。则只需要求出当K为1时,节点个数即可。

代码实现

public int getKLevelNodeCount(TreeNode root, int k) {
        if(root == null || k <= 0) {
            return 0;
        }
        if(k == 1) {
            return 1;
        }
        return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);
    }

二叉树的最大高度

🎉递归计算出左右子树的最大高度,然后比较,输出最大的值 + 1(根节点)。高度的累加也是在递归回退的过程。我们在脑海中要能想清楚这样的递归过程。

代码实现

public int getHight(TreeNode root) {
        if(root == null) {
            return 0;
        }
        int tmp1 = getHight(root.left);
        int tmp2 = getHight(root.right);
        return tmp1 > tmp2 ? tmp1 + 1: tmp2 + 1;
    }

二叉树中查找某个数据

😉可以采取前序遍历法去遍历整棵树,只不过在递归左右子树时,去判断,如果符合条件就返回,不在去递归。

代码实现

public TreeNode find(TreeNode root, char val) {
        if(root == null) {
            return null;
        }
        if(root.val == val) {
            return root;
        }
        TreeNode tmp1 = find(root.left, val);
        if(tmp1 != null) {
            return tmp1;
        }
        TreeNode tmp2 = find(root.right, val);
        if(tmp2 != null) {
            return tmp2;
        }
        return null;
    }

层序遍历二叉树

层序遍历规则:从上到下,从左到右。

🎈这里采取队列结构特点,队列是怎么入队就怎么出队,入队和出队的顺序是一致的。那么我们只需要保证二叉树从上到下,从左到右去入这个队列,出队时就能保证也是这个顺序。

🎈可以采取用cur去遍历整棵树,树根肯定是层序遍历的第一个数据,直接入树根到队列,判断队列为不为空,不为空则出队列给cur,然后打印数据。接下来分别入根的左右子树,然后再去判断队列,不为空则出左子树给cur,打印数据,再入这棵树的左右子树,出根的右树给cur,打印数据,再入这棵树的左右子树,依次循环直到队列为空。

代码实现

public void levelOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode cur = root;
        queue.offer(cur);
        while(!queue.isEmpty()) {
            cur = queue.poll();
            System.out.print(cur.val + " ");
            if(cur.left != null) {
                queue.offer(cur.left);
            }
            if(cur.right != null) {
                queue.offer(cur.right);
            }
        }

    }

根据前序遍历字符串构建一颗二叉树

😊"abc##de#g##f###",这是一个前序遍历的字符串,#代表空树。我们也根据前序遍历去构建这颗二叉树,如果不为空树就去new节点,然后递归去构建这个节点的左右子树,是#就继续向后遍历字符串。

🤨需要注意的是我们需要一个变量去遍历字符串,而我们采用的是递归的方式,如果是局部变量,那么每次递归进来的时候,该变量都会被重置。所以考虑将该变量定义为成员属性,可以起到累加的效果。

代码实现

private static int i = 0;
    public static TreeNode createTree(String str) {

        //先构造根节点,然后递归构造左右子树
        char tmp = str.charAt(i);
        TreeNode newNode = null;
        if(tmp != '#') {
            i++;
            newNode = new TreeNode(tmp);
            newNode.left = createTree(str);
            newNode.right = createTree(str);
        }else {
            i++;
        }
        return newNode;
    }

小结:

🐵对于二叉树的一些操作,最关键的就是递归的核心思想:子问题思路。需要我们大量去思考,去实践。

相关文章:

  • 湖仓一体电商项目(二十四):合并Iceberg小文件
  • Java中如何向一个HashSet对象中添加元素呢?
  • 静态HTML CSS网站制作成品 简单的学生网页作业代码【带视频演示】
  • 达梦数据库整合在springboot的使用教程
  • 【Linux】Linux的基本指令(Linux入门、用户的创建和切换)
  • C语言进阶——动态内存管理
  • C#面向对象程序设计课程实验一:实验名称:C#语言基础、程序流程控制
  • 公司级攻防比赛常用的突破方法
  • 多线程概述(线程创建,方法(等待,通知,加入,睡眠,礼让,中断),上下文切换,死锁,守护线程与用户线程)
  • 编译方式安装nginx
  • 【第48篇】MaxViT:多轴视觉转换器
  • shell 基础
  • 《uni-app》uni-app实现疯狂点赞效果(一)
  • service 自我升级遇到的问题
  • 安全测试场景下怎样突破内网防御机制
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • CSS 三角实现
  • JavaScript的使用你知道几种?(上)
  • JavaScript实现分页效果
  • Laravel 实践之路: 数据库迁移与数据填充
  • Linux下的乱码问题
  • Making An Indicator With Pure CSS
  • python 装饰器(一)
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • web标准化(下)
  • 代理模式
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 和 || 运算
  • 讲清楚之javascript作用域
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 如何进阶一名有竞争力的程序员?
  • 数据仓库的几种建模方法
  • 我看到的前端
  • 延迟脚本的方式
  • 一个项目push到多个远程Git仓库
  • 译米田引理
  • 怎么将电脑中的声音录制成WAV格式
  • 阿里云ACE认证之理解CDN技术
  • $(function(){})与(function($){....})(jQuery)的区别
  • %check_box% in rails :coditions={:has_many , :through}
  • (2)nginx 安装、启停
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (Note)C++中的继承方式
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (离散数学)逻辑连接词
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (十八)三元表达式和列表解析
  • (顺序)容器的好伴侣 --- 容器适配器
  • (转)甲方乙方——赵民谈找工作
  • *p++,*(p++),*++p,(*p)++区别?
  • . NET自动找可写目录