【java数据结构】二叉树

【java数据结构】二叉树

  • 一、 认识二叉树
      • 1.1 二叉树的概念
      • 1.2 二叉树的特性:
      • 1.3 两种特殊的二叉树:
      • 1.4 二叉树的性质:
      • 1.5 二叉树的存储:
  • 二、 实现二叉树
      • 2.1 二叉树节点的定义:
      • 2.2 二叉树的基本操作:
        • 获取树中节点的个数
        • 获取叶子节点的个数
        • 获取第K层节点的个数
        • 获取二叉树的高度
        • 检测值为value的元素是否存在
        • 判断一棵树是不是完全二叉树
      • 2.3 二叉树的遍历:
        • 前序遍历
        • 中序遍历
        • 后序遍历
        • 层序遍历

此篇博客希望对你有所帮助(帮助你了解二叉树,二叉树主要运用递归,有那块代码不懂或者理解不了的,一定要进行画图去理解),不懂的或有错误的也可在评论区留言,错误必改评论必回!!!持续关注,下一篇博客是二叉树面试题!!!整篇博客的代码都在Gitee中(代码链接放在文章结尾)。

一、 认识二叉树

1.1 二叉树的概念

二叉树是一个有限的节点集合,这个集合可能是空的(此时称为空二叉树),或者由一个根节点以及两个互不相交的、分别被称为左子树和右子树的二叉树所组成。

1.2 二叉树的特性:

  1. 每个节点至多有两个子节点,分别被称为左子节点和右子节点。
  2. 左子树和右子树的次序不能颠倒。
  3. 二叉树是有序树,因为即使树中节点没有值,其左右子树的区分也仍然有意义。

在这里插入图片描述

对于任意二叉树都是由以下几种情况复合而成:
在这里插入图片描述

1.3 两种特殊的二叉树:

  1. 满二叉树: 一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且结点总数是(2^k)-1 ,则它就是满二叉树。
  2. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

在这里插入图片描述

1.4 二叉树的性质:

二叉树(Binary Tree)具有一些重要的性质,这些性质对于理解和操作二叉树非常有帮助。下面是二叉树的一些常见性质:

  • 每个节点最多有两个子节点:每个节点最多有一个左子节点和一个右子节点。这意味着一个节点的度数(Degree)最大为2。
  • 左子树和右子树的顺序是固定的:在二叉树中,左子树位于父节点的左侧,右子树位于父节点的右侧。改变左右子树的顺序将产生不同的二叉树。
  • 节点的度数:节点的度数是指该节点的子节点数量。二叉树中,节点的度数最大为2,即一个节点最多有两个子节点。
  • 叶节点(叶子节点):叶节点是没有子节点的节点,也可以称为终端节点。
  • 节点的层级(Level):根节点的层级为1,其余节点的层级为其父节点的层级加1。
  • 树的高度(Height):树的高度是从根节点到最远叶节点的最长路径上的边数。叶节点的高度为0,空树的高度为-1。
  • 完全二叉树(Complete Binary Tree)性质:在完全二叉树中,除了最后一层外,其他层的节点都是满的,且最后一层的节点都尽量靠左排列。
  • 满二叉树(Full Binary Tree)性质:在满二叉树中,除了叶节点外,每个节点都有两个子节点。
  • 二叉搜索树(Binary Search Tree)性质:二叉搜索树是一种特殊的二叉树,它满足以下性质:对于树中的每个节点,其左子树中的所有节点都小于该节点的值,而其右子树中的所有节点都大于该节点的值。
  • 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 2^(i-1) (i > 0)个结点。
  • 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 (2^k) - 1 (k>=0)。
  • 对任何一棵二叉树, 如果其叶结点个数为 n0,度为2的非叶结点个数为 n2,则有 n0 = n2 + 1。
  • 具有n个结点的完全二叉树的深度k为log2 (n + 1) 上取整。
  • 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为 i 的结点有:
    • 若 i > 0,双亲序号:(i - 1) / 2;i = 0,i 为根结点编号,无双亲结点。
    • 若 2i + 1< n,左孩子序号:2i + 1,否则无左孩子。
    • 若 2i + 2 < n,右孩子序号:2i + 2,否则无右孩子。

1.5 二叉树的存储:

  1. 链式存储法(链表表示法)
    链式存储法使用节点(Node)来存储二叉树的每个元素,每个节点包含三个部分:

数据域(data):存储节点的值。
左指针(left):指向左子节点。
右指针(right):指向右子节点。

这种方法的优点是可以灵活地表示任意形状的二叉树,节省空间(不需要为空的子节点分配空间)。缺点是需要额外的指针空间,并且遍历二叉树时可能涉及频繁的指针操作。

  1. 顺序存储法(数组表示法)
    顺序存储法使用一个数组来存储二叉树的节点。对于完全二叉树,节点在数组中的位置可以通过以下公式确定:

对于根节点,其索引为 0。
对于节点索引为 i 的左子节点,其索引为 2i + 1。
对于节点索引为 i 的右子节点,其索引为 2
i +2。

这种方法的优点是操作简单,通过索引关系可以直接访问任意节点的子节点和父节点。缺点是对于非完全二叉树,会浪费空间(因为数组中需要填充空节点)。

二、 实现二叉树

2.1 二叉树节点的定义:

    static class TreeNode{public char val;public TreeNode left;//左孩子的引用public TreeNode right;//右孩子的引用public TreeNode(char val) {this.val = val;}}

2.2 二叉树的基本操作:

    // 获取树中节点的个数int size(TreeNode root){}// 获取叶子节点的个数int getLeafNodeCount(TreeNode root){}// 子问题思路-求叶子结点个数
// 获取第K层节点的个数int getKLevelNodeCount(TreeNode root,int k){}// 获取二叉树的高度int getHeight(TreeNode root){}// 检测值为value的元素是否存在TreeNode find(TreeNode root, int val){}// 判断一棵树是不是完全二叉树boolean isCompleteTree(TreeNode root){}
获取树中节点的个数

代码思路:
1.判断数是否为空。为空节点个数为0。
2.定义一个全局int型变量len,因为需要递归,如果将len定义为局部变量,在每次递归时len都是我们给定的初始值。

    // 获取树中节点的个数public int len = 0;int size(TreeNode root) {if (root == null) {return 0;}len++;size(root.left);size(root.right);return len;}
获取叶子节点的个数

代码思路:
两种解决方案:
1.先去判断树是否为空
(1)
1.定义一个全局变量size,和上面思路一样。
2.通过叶子节点的概念,我们熟知,我们需要递归每一个节点,然后去判断节点的度是否为0,为0,则是叶子节点,否则,反之。
(2)
1.不去定义全局变量,直接递归。
2.递归到每个节点都去判断一次节点的度是否为0,如果为0,则返回到上次递归语句中。

    // 获取叶子节点的个数public int size = 0;int getLeafNodeCount(TreeNode root) {if (root == null) {return 0;}getLeafNodeCount(root.left);if (root.right == null) {size++;}getLeafNodeCount(root.right);return size;}int getLeafNodeCount2(TreeNode root) {if (root == null) return 0;if (root.left == null && root.right == null) {return 1;}return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);}
获取第K层节点的个数

代码思路:
1.先去判断代码是否为空
2.因为是获得第K层的节点个数,我们可以采用逆序的思想:
将根那一层当成第K层,然后进行递归,每递归一次K-1,当递归到K==1时,此时就是我们想要得到的第K层

// 获取第K层节点的个数int getKLevelNodeCount(TreeNode root, int k) {if (root == null) {return 0;}if (k == 1) {return 1;}return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);}
获取二叉树的高度

代码思路:
1.先判断树是否为空
2.分别对每个节点进行左递归和右递归
3.判断这个节点左递归和右递归那个递归的次数多,返回那个值,最后返回的值就是树的高度。

    //    // 获取二叉树的高度int getHeight(TreeNode root) {if (root == null) return 0;int leftH = getHeight(root.left);int rightH = getHeight(root.right);return leftH > rightH ? leftH + 1 : rightH + 1;}
检测值为value的元素是否存在

代码思路:
1.先判断树是否为空
2.然后判断根节点是否为value值,如果不是,则进行递归
3.如果找到value值,则需要定义一个节点ret来接受找到的value值的节点,进行一步一步返回。这里返回的将一直是找到的ret节点

//    // 检测值为value的元素是否存在TreeNode find(TreeNode root, char val){if(root==null){return null;}if(root.val==val){return root;}TreeNode ret=find(root.left,val);if(ret!=null){return ret;}ret= find(root.right,val);return ret;}
判断一棵树是不是完全二叉树

代码思路:
1.这里需要借助所学的队列(先进先出)
2.首先判断树是否为空
3.将根节点先存入到队列当中,这里需要定义一个cur来标记出队列的节点
4.当出一个节点,就将这个节点的左右孩子节点存入队列中,不管左右孩子是否为空
这里值得注意的是:存入队列当时中的节点为null,queue.isEmpty()不为空的(判断 的是队列中的元素个数)
5.当cur为null时,跳出queue.isEmpty()循环,这个时候判断队列当中是否还有除了nul,以为的其他元素,如果有其他元素,则这就不是一个完全二叉树,反之,则不是完全二叉树。

//    // 判断一棵树是不是完全二叉树boolean isCompleteTree(TreeNode root){Queue<TreeNode> queue=new LinkedList<>();if(root==null){return true;}queue.offer(root);TreeNode cur;while(!queue.isEmpty()){cur=queue.poll();if(cur!=null) {queue.offer(cur.left);queue.offer(cur.right);}else{break;}}while(!queue.isEmpty()){if(queue.peek()==null){queue.poll();}else{return false;}}return true;}

完全二叉树图解:
在这里插入图片描述
非完全二叉树图解:
在这里插入图片描述

2.3 二叉树的遍历:

遍历是访问树中所有节点的过程,主要有以下几种方式:

  • 前序遍历(Preorder Traversal):根节点 -> 左子树 -> 右子树
  • 中序遍历(Inorder Traversal):左子树 -> 根节点 -> 右子树(对于二叉搜索树,这是升序访问所有节点的方式)
  • 后序遍历(Postorder Traversal):左子树 -> 右子树 -> 根节点
  • 层次遍历(Level Order Traversal):按层次从上到下、从左到右访问节点(通常使用队列实现)。

举例:
在这里插入图片描述
前序遍历:A B C D E F
中序遍历:C B D A E F
后序遍历 :C D B F E A
层次遍历 :A B E C D F

前序遍历
   // 前序遍历void preOrder(TreeNode root){if(root==null){return;}System.out.println(root.val+" ");preOrder(root.left);preOrder(root.right);}
中序遍历
    // 中序遍历void inOrder(TreeNode root){if(root==null){return;}inOrder(root.left);System.out.println(root.val+" ");inOrder(root.right);}
后序遍历
// 后序遍历void postOrder(TreeNode root){if(root==null){return;}postOrder(root.left);postOrder(root.right);System.out.println(root.val+" ");}
层序遍历

代码思路:
1.需要借助对列来实现。
2.首先先判断树是否为空。
3.不为空,先将根节点存进去,然后定义一个节点cur来接受从队列中出来的节点,判断弹出的节点左右孩子节点是否为空,不为空的存入到队列当中,打印弹出的元素。

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

此篇博客的代码!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智源推出小时级超长视频理解大模型Video-XL

北京智源人工智能研究院联合上海交通大学、中国人民大学、北京大学和北京邮电大学等高校推出了一款名为Video-XL的超长视频理解大模型。这款模型是多模态大模型核心能力的重要展示&#xff0c;也是向通用人工智能&#xff08;AGI&#xff09;迈进的关键步骤。与现有多模态大模型…

《链表篇》---两两交换链表中的节点(中等)

题目传送门 1.定义一个虚拟节点链接链表 2.定义一个当前节点指向虚拟节点 3.在当前节点的下一个节点和下下一个节点都不为null的情况下。 定义 node1和node2。保存当前节点后面两个节点的地址。cur.next node2;node1.next node2.next;node2.next node1;cur node1; 4.返回re…

Oracle视频基础1.3.4练习

1.3.4 检查数据库实例启动情况&#xff0c;进程以及进程间通信 ps -ef | grep oracle ipcs启动数据库实例&#xff0c; 用缺省spfilewilson ls -l env | grep ORACLE sqlplus /nolog conn / as sysdba startup shutdown immediate exit clear新创建pfile和spfile指定pfile数…

图书管理系统汇报

【1A536】图书管理系统汇报 项目介绍1.用户登录注册功能1. 1用户角色管理2.图书管理功能2.1 添加图书2.2 编辑图书2.3 删除图书 3.图书搜索和筛选3.1 图书搜索3.2 图书筛选 4.图书借阅、图书归还4.1 图书借阅4.2 图书归还 5.用户信息管理5.1上传头像5.2修改头像5.3 修改密码 项…

JetCache启动循环依赖分析

问题呈现 项目性能优化&#xff0c;需要将本地内存&#xff08;JVM内存&#xff09;替换为本地Redis&#xff08;同一个Pod中的Container&#xff09;&#xff0c;降低JVM内存和GC的压力&#xff0c;同时引入了JetCache简化和统一使用&#xff08;对JetCache也做了扩展&#x…

使用二进制安装K8S 多master节点 高可用集群

目录 1.初始化 1.1 配置静态IP 1.2 配置主机名 1.3 配置hosts文件 1.4 配置主机之间无密码登录&#xff0c;每台机器都按照如下操作 1.5 关闭firewalld防火墙&#xff0c;在xianchaomaster1、xianchaomaster2、xianchaomaster3、xianchaonode1上操作&#xff1a; 1.…

vue的基本使用

简介 vue组件 三个部分组成&#xff1a;结构、样式、逻辑 文本插值 类似于java的spel表达式 属性绑定 綁定是单向绑定的&#xff0c;修改输入框无法改变原本的&#xff0c;只能读&#xff0c;不能写 <input :value"name" placeholder"Type your name"&g…

从APP小游戏到Web漏洞的发现

一、前因&#xff1a; 在对一次公司的一个麻将游戏APP进行渗透测试的时候发现&#xff0c;抓到HTTP请求的接口&#xff0c;但是反编译APK后发现没有在本身发现任何一个关于接口或者域名相关的关键字&#xff0c;对此感到了好奇。 于是直接解压后everything搜索了一下&#xff…

【有啥问啥】视频插帧算法技术原理详解

视频插帧算法技术原理详解 引言 视频插帧&#xff08;Video Interpolation&#xff09;技术&#xff0c;作为计算机视觉领域的一项重要应用&#xff0c;旨在通过算法手段在已有的视频帧之间插入额外的帧&#xff0c;从而提升视频的帧率&#xff0c;使其看起来更加流畅。这一技…

【温酒笔记】DMA

参考文档&#xff1a;野火STM32F103 网友资料整理 1. Direct Memory Access-直接内存访问 DMA控制器独立于内核 是一个单独的外设 DMA1有7个通道DMA2有5个通道DMA有四个等级&#xff0c;非常高&#xff0c;高&#xff0c;中&#xff0c;低四个优先级如果优先等级相同&#xf…

精选云手机平台推荐:五大知名云手机品牌汇总

云手机目前已经在很多行业开始应用&#xff0c;特别是对于需要多设备操作、稳定性能和账号安全保障的用户。下面就为大家推荐几款优质云手机平台&#xff0c;一起来看看各大品牌有什么优势。 1. Ogphone云手机 Ogphone云手机凭借强大的海外网络连接和群控性能受到各行业用户的欢…

C++设计模式结构型模式———适配器模式

文章目录 一、引言二、适配器模式三、类适配器四、总结 一、引言 适配器模式是一种结构型设计模式&#xff0c;它在日常生活中有着广泛的应用&#xff0c;比如各种转换接头和电源适配器&#xff0c;它们的主要作用是解决接口不兼容的问题。就像使用电源适配器将220V的市电转换…

生产车间怎么管?设备、生产、物料管理方法更好

我们都知道&#xff0c;面对竞争激烈的大环境&#xff0c;生产车间对于企业的重要性不言而喻&#xff0c;它是企业发展的关键所在。 生产车间管理是一项复杂且系统性很强的工作&#xff0c;涉及多个重要方面。其中&#xff0c;人员管理是核心之一&#xff0c;员工作为生产活动…

Prometheus套装部署到K8S+Dashboard部署详解

1、添加helm源并更新 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update2、创建namespace kubectl create namespace monitoring 3、安装Prometheus监控套装 helm install prometheus prometheus-community/prome…

Redis 主从同步 总结

前言 相关系列 《Redis & 目录》《Redis & 主从同步 & 源码》《Redis & 主从同步 & 总结》《Redis & 主从同步 & 问题》 参考文献 《Redis的主从复制和哨兵机制详解》 概述 简介 主从同步的本质是数据复制机制。主从同步机制用于将master…

认证鉴权框架之—sa-token

一、概述 Satoken 是一个 Java 实现的权限认证框架&#xff0c;它主要用于 Web 应用程序的权限控制。Satoken 提供了丰富的功能来简化权限管理的过程&#xff0c;使得开发者可以更加专注于业务逻辑的开发。 二、逻辑流程 1、登录认证 &#xff08;1&#xff09;、创建token …

PCM5102A具有PLL和32位、384kHz PCM/I2S接口的2.1VRMS、112dB音频立体声DAC

PCM5102A外观和丝印 1 特性 1•超低带外噪声 •具有BCK基准的高性能集成音频锁相环(PLL)&#xff0c;可在内部生成SCK •直接线路电平2.1VRMS输出 •无需隔直电容 •线路电平输出支持低至1kΩ的负载 •智能静音系统&#xff1b;软斜升或斜降搭配模拟静音&#xff0c;实现120dB…

BUG的跟踪管理

目录 一、bug的类型 二、bug的等级 1、致命错误&#xff1a;------blocker 2、严重错误&#xff1a;------critical 3、一般错误&#xff1a;------major 4、细微错误&#xff1a;------minor 5、改进建议:------enhancement 6、bug类型及等级判断 三、bug的生命周期(…

Spring 框架环境搭建

一、环境要求 JDK版本&#xff1a; JDK1.7及以上版本 Spring版本&#xff1a; Spring5.x版本 二、新建Maven项目 1. 创建 Maven 的普通 Java 项⽬ 2.设置项目坐标 3.设置项目的Maven环境 4.设置项目的名称和存放的工作空间 三、调整项目环境 1.修改JDK版本 properties&g…

网络安全包含哪些方面?如何加强网络安全建设?

系统安全、应用安全、物理安全、管理安全等都属于网络安全。 从大的角度&#xff0c;如系统安全来看&#xff0c;可以理解为在系统生命周期内应用系统安全工程和系统安全管理方法&#xff0c;辨识系统中的隐患&#xff0c;并采取有效的控制措施使其危险性最小。这包括操作系统的…