Java Collection(3)——BinaryTree(二叉树)

前言

1.掌握树的基本概念
2.掌握二叉树概念及特性
3.掌握二叉树的基本操作
后面的优先级队列(大根堆,小根堆)也是基于二叉树实现的,所以理解好二叉树至关重要

1.树形结构

1.1描述

树是一种非线性的数据结构,它是由不为零个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上叶朝下

1.2特点

  1.  一棵树只有一个根节点,并且根节点没有前驱节点
    
  2.  除根结点外,其余节点分成n个(n>0)互不相交的集合,每个集合又是一颗与树类似的子树。每颗子树有且只有一个前驱节点,任意个后继节点
    
  3.  树是递归定义的
    

在这里插入图片描述

1.3概念(重要)

  1.  节点的度:一个节点拥有的子节点的数量就是该节点的度;例如A节点的度为2
    
  2.  树的度:该树种所有节点的度取**最大值**
    
  3.  叶子节点/终端节点:度为零的节点
    
  4.  双亲结点/父节点:一个节点拥有子节点,那么该节点就是其子节点的父节点
    
  5.  子节点:一个节点拥有父节点,那么该节点就是其父节点的子节点
    
  6.  根节点:没有父节点的节点
    
  7.  结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
    
  8.  树的高度/深度:该树中节点的层次取最大值
    

剩下的几个概念很少提及,知道即可
非终端结点或分支结点:度不为0的结点
兄弟结点:具有相同父结点的结点互称为兄弟结点
堂兄弟结点:双亲在同一层的结点互为堂兄弟
结点的祖先:从根到该结点所经分支上的所有结点;例如:D节点的祖先有A和B
子孙:以某结点为根的子树中任一结点都称为该结点的子孙;例如:以B为根节点,它的子孙有D和E

1.4表示方式

表示方式知道一个最常用的就好了:孩子兄弟表示法
在这里插入图片描述

1.5树的应用

文件系统管理(目录和文件)
在这里插入图片描述
将电脑的所有文件看成一棵树,这里的C盘就相当于根节点,C盘下有四个子节点(文件夹/目录),每个目录下又有n个子节点

2.二叉树

2.1概念:

树的度<=2的树形结构
在这里插入图片描述

2.2特点

由上图可知

  1.  二叉树不存在度大于2的结点
    
  2.  二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
    

二叉树有以下几种情况
在这里插入图片描述

2.3两种特殊的二叉树

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

在这里插入图片描述

2.4二叉树的性质

  1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 2^(i - 1)(i>0)个结点
  2. 若规定根结点的层数为1,则一棵深度为k非空二叉树的总结点数为(2^k) - 1
  3. 对任何一棵二叉树, 如果其**叶结点**个数为 n0, **度为2的非叶结点**个数为 n2,则有**n0=n2+1**
    
  4. 具有n个结点完全二叉树的深度k=log₂(n)向上取整

2.5完全二叉树的节点组成**(我自己总结的规律)

设总结点数N,度为1的节点数n1,度为2的节点数n2,度为1的节点数n0

  1.  完全二叉树中度为1的节点要么有一个,要么没有
    
  2.  当总结点数目为奇数时,没有度为1的节点,满足关系式N=n2+n0,且n2=n0-1;当总结点数为偶数时,有一个度为1的节点,满足关系式N=n2+n0+n1,且n2=n0-1
    

2.5二叉树的存储方式

二叉树的存储结构分为:顺序存储类似于链表的链式存储
下篇博文会在完全二叉树的基础上实现优先级队列/堆(顺序存储);本文模拟实现二叉树/(下篇博文的二叉搜索树)用类似链表的方式,非完全二叉树使用顺序存储会浪费空间。
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式

//二叉表示法public static class BTNode {BTNode left;//左孩子的引用BTNode right;//右孩子的引用int val;//数据域public BTNode(int val) {this.val = val;}}
//三叉表示法public static class BTNode {BTNode left;//左孩子的引用BTNode right;//右孩子的引用BTNode parent;//当前节点的根节点/父节点int val;//数据域public BTNode(int val) {this.val = val;}}

2.6二叉树的基本操作

2.6.1前置说明

学习二叉树的基本操作之前,首先得创建一颗二叉树,由于大家对于二叉树还不够了解,所以我先手动创建一颗二叉树,等熟悉二叉树的基本操作后再来研究二叉树真正的创建方式

public BTNode getRoot() {return root;}//二叉表示法public static class BTNode {BTNode left;//左孩子的引用BTNode right;//右孩子的引用int val;//数据域public BTNode(int val) {this.val = val;}}private BTNode root;//手动创建二叉树public void createBinaryTree(){BTNode btNode1 = new BTNode(1);BTNode btNode2 = new BTNode(2);BTNode btNode3 = new BTNode(3);BTNode btNode4 = new BTNode(4);BTNode btNode5 = new BTNode(5);BTNode btNode6 = new BTNode(6);BTNode btNode7 = new BTNode(7);BTNode btNode8 = new BTNode(8);btNode1.left = btNode2;btNode2.left = btNode4;btNode2.right = btNode5;btNode1.right = btNode3;btNode3.left = btNode6;btNode3.right = btNode7;btNode4.left = btNode8;root = btNode1;}

在这里插入图片描述

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式下篇博文讲到二叉搜索树再介绍

2.6.2二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓遍历,就是沿着某条搜索路线,对树中的每一个节点做一次且仅做一次访问操作,访问操作依赖于实际的应用场景(打印节点,节点+1)
对于二叉树来说,常用的遍历方式有四种(前序遍历,中序遍历,后序遍历,层序遍历),这里先介绍前三种

  1.  前序遍历(Preorder Traversal):访问根节点——>根的左子树——>根的右子树
    
  2.  中序遍历(Inorder Traversal):根的左子树——>根节点——>根的右子树
    
  3.  后序遍历(Postorder Traversal):根的左子树——>根的右子树——>根节点
    

这图是前序遍历的路径
在这里插入图片描述
以这张图片的二叉树为准,三种遍历方式的访问顺序如下
前序遍历:1->2->3->4->5->6
中序遍历:3->2->1->5->4->6
后序遍历:3->2->5->6->4->1

//前序遍历public void preOrder(BTNode root){if (root == null) return;//打印当前节点System.out.print(root.val+" ");//遍历左树preOrder(root.left);//遍历右树preOrder(root.right);}//中序遍历public void inOrder(BTNode root){if (root == null) return;//遍历左树inOrder(root.left);//打印当前节点System.out.print(root.val+" ");//遍历右树inOrder(root.right);}//后序遍历public void postOrder(BTNode root){if (root == null) return;//遍历左树postOrder(root.left);//遍历右树postOrder(root.right);//打印当前节点System.out.print(root.val+" ");}

2.6.3二叉树的基本操作

1.获取树中节点的个数

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

2.获取叶子节点的个数

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

3.获取第K层节点的个数

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

4.获取二叉树的高度

public int getHeight(BTNode root){if (root == null) return 0;int countLeft = getHeight(root.left);int countRight = getHeight(root.right);return (countLeft >= countRight ? countLeft + 1 : countRight + 1);}

5.检测值为value的元素是否存在

public Boolean findValue(BTNode root, int val){if (root == null) return false;if (root.val == val) return true;if(findValue(root.left,val)) return true;if(findValue(root.right,val)) return true;return false;}

6.层序遍历初阶

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

7.层序遍历进阶
在这里插入图片描述

public List<List<BTNode>> levelOrder2(BTNode root){//两种List<List<BTNode>> ret = new ArrayList<>();if (root == null) return ret;Queue<BTNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){int size = queue.size();List<BTNode> temp = new ArrayList<>();while (size != 0) {BTNode cur = queue.poll();temp.add(cur);size--;if (cur != null && cur.left != null) {queue.offer(cur.left);}if (cur != null && cur.right != null) {queue.offer(cur.right);}}ret.add(temp);}return ret;}

8.判断完全二叉树

public Boolean isCompleteTree (BTNode root){if (root == null) return true;Queue<BTNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){BTNode cur = queue.poll();if (cur != null){queue.offer(cur.left);queue.offer(cur.right);}else {break;}}while (!queue.isEmpty()){BTNode cur = queue.poll();if (cur != null) return false;}return true;}

三.小结

至此,二叉树的基本操作已经介绍完毕了,下篇博文会在二叉树的基础上延伸出其他的结构,例如:二叉搜索树,优先级队列

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

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

相关文章

[Echarts]图例换行时icon对齐标题

当前效果 目标效果 让图例中的“点”和标题同一行 代码 const data [{value: 100,name: 未标注},{value: 100,name: 已标注},{value: 100,name: 标注中} ];option {tooltip: {backgroundColor: #fff,extraCssText: box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);,backgro…

Scala编程_实现Rational的基本操作

在Scala中实现一个简单的有理数&#xff08;Rational&#xff09;类&#xff0c;并对其进行加法、比较等基本操作. 有理数的定义 有理数是可以表示为两个整数的比值的数&#xff0c;通常形式为 n / d&#xff0c;其中 n 是分子&#xff0c;d 是分母。为了确保我们的有理数始终…

责任链模式如何减少模块之间的耦合

责任链模式如何减少模块之间的耦合 在复杂的软件系统中&#xff0c;模块之间的耦合是一个常见的问题。高耦合的代码不仅增加了维护成本&#xff0c;还会导致系统的扩展性和灵活性受限。当我们需要为不同的请求设计灵活的处理逻辑时&#xff0c;传统的硬编码方式会将请求的发送…

【最新】DeepSeek 实用集成工具有那些?

deepseek 系列github仓库地址 【主页】deepseek-aiDeepSeek-R1DeepSeek-V3DeepSeek-VL2【本文重点介绍】awesome-deepseek-integration 注意&#xff1a;以下内容来自awesome-deepseek-integration DeepSeek 实用集成&#xff08;awesome-deepseek-integration&#xff09; 将…

如何在Python下实现摄像头|屏幕|AI视觉算法数据的RTMP直播推送

技术背景 在直播应用开发中&#xff0c;RTMP推流是核心功能之一。本文将结合大牛直播SDK的Python接口实现&#xff0c;详细讲解如何在Python环境下进行RTMP推流开发。好多开发者都知道&#xff0c;在发布Python的RTMP推流demo示例之前&#xff0c;我们十年前已经发布了非常稳定…

不用 Tomcat?SpringBoot 项目用啥代替?

在SpringBoot框架中&#xff0c;我们使用最多的是Tomcat&#xff0c;这是SpringBoot默认的容器技术&#xff0c;而且是内嵌式的Tomcat。 同时&#xff0c;SpringBoot也支持Undertow容器&#xff0c;我们可以很方便的用Undertow替换Tomcat&#xff0c;而Undertow的性能和内存使…

LLM训练中常用的Benchmarks

在当今人工智能领域,大语言模型(LLM)凭借其在理解和生成人类自然语言文本方面的卓越表现,成为了备受瞩目的焦点。然而,随着LLM的广泛应用,如何对其性能进行准确、全面的评估成为了一个关键问题。在这样的背景下,大语言模型基准测试应运而生,它是评估LLM不可或缺的重要工…

基于深度学习的医学CT图像肺结节智能检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

Selenium | 无法正常打开Google Chrome浏览器 转 Edge Chrome

目录 背景案例 换成 Edge Chrome 驱动下载 配置环境 代码案例 测试结果 背景案例 Python正常&#xff0c;环境正常&#xff0c;驱动正常&#xff0c;但是就是打不开浏览器&#xff0c;就是一直报错&#xff0c;导致很烦躁 换成 Edge Chrome 与 Google Chrome浏览器一样…

【JavaEE】文件操作和IO

【JavaEE】文件操作和IO 一、认识文件1.1 狭义和广义的文件概念1.2 文件路径1.3 文件的分类 二、Java 中操作⽂件2.1 File类2.2 代码演示 三、文件内容的读写 —— 数据流3.1 字节流和字符流字节流字符流 3.2 特别注意 四、实战演示4.1 查找删除文件4.2 普通文件的复制4.3 文件…

【数据挖掘】通过心脏病数据案例熟悉数据挖掘的完整过程

心脏病数据挖掘过程 一、加载数据源 # 如果没有安装数据源所依赖的库&#xff0c;则先安装数据源所在的python库: pip install ucimlrepo # 引入pandas和ucimlrepo import pandas as pd from ucimlrepo import fetch_ucirepo# fetch dataset Heart Disease dataset的Id为45 h…

【Golang】第二弹-----变量、基本数据类型、标识符

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;Golang &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一、变量 1.1基本介绍…

go个人论坛项目

搭建个人论坛 项目地址&#xff1a;MyForum: goginvue搭建论坛 - Gitee.com PS&#xff1a;有些地方没有写好&#xff0c;请选择性查看 初始化项目 创建目录结构 利用ini配置初始化框架 [server] AppMode debug HttpPort :3000 JwtKey "dhjasdkajh321"[databa…

日志系统项目——准备工作了解类的设计模式如单例模式、工厂模式、代理模式

1.六大原则 1.1 单一职责原则 类的职责应该单⼀&#xff0c;⼀个⽅法只做⼀件事。职责划分清晰了&#xff0c;每次改动到最⼩单位的⽅法或 类。 使⽤建议&#xff1a;两个完全不⼀样的功能不应该放⼀个类中&#xff0c;⼀个类中应该是⼀组相关性很⾼的函 数、数据的封装 ⽤例…

股指期货基差怎么计算?公式介绍

先说说啥是基差。简单来说&#xff0c;基差就是股指期货价格和现货指数价格之间的差值。就好比你手里有一张股票指数的“未来提货券”&#xff08;股指期货&#xff09;&#xff0c;但你现在就能买到股票指数&#xff08;现货指数&#xff09;&#xff0c;这两者之间的价格差&a…

Comfyui 与 SDwebui

ComfyUI和SD WebUI是基于Stable Diffusion模型的两种不同用户界面工具&#xff0c;它们在功能、用户体验和适用场景上各有优劣。 1. 功能与灵活性 ComfyUI&#xff1a;ComfyUI以其节点式工作流设计为核心&#xff0c;强调用户自定义和灵活性。用户可以通过连接不同的模块&…

深圳传音控股手机软件开发岗内推

1.负责手机UI、功能开发 2.负责手机具体模块(通信、多媒体、系统、应用)独立开发 3.负责手机软件调试、log分析等 推荐码&#xff1a;EVHPB3 &#xff0c;简历第一时间送到HR面前&#xff5e;

never_give_up

一个很有意思的题&#xff1a; never_give_up - Bugku CTF平台 注意到注释里面有1p.html&#xff0c;我们直接在源代码界面看&#xff0c;这样就不会跳转到它那个链接的&#xff1a; 然后解码可得&#xff1a; ";if(!$_GET[id]) {header(Location: hello.php?id1);exi…

Aliyun CTF 2025 web 复现

文章目录 ezoj打卡OKoffens1veFakejump server ezoj 进来一看是算法题&#xff0c;先做了试试看,gpt写了一个高效代码通过了 通过后没看见啥&#xff0c;根据页面底部提示去/source看到源代码&#xff0c;没啥思路&#xff0c;直接看wp吧&#xff0c;跟算法题没啥关系,关键是去…

BigFoot EventAlertMod lua

BigFoot EventAlertMod lua脚本插件&#xff0c;追踪当前目标的DOT&#xff0c;自身的HOT&#xff0c;持续时间监控 D:\Battle.net\World of Warcraft\_classic_\Interface\AddOns\EventAlertMod 想知道技能的ID&#xff0c;执行命令如下&#xff1a;本例子为“神圣牺牲” /e…