【数据结构】--二叉树--堆(上)

一、树的概念和结构

概念:

树是一种非线性的数据结构,他是由n(n>=0)个有限结点组成一个具有层次关系的集合。其叫做树,是因为他倒过来看就和一棵树差不多,其实际上是根在上,树枝在下的。

树的特点:

1、其有一个特殊的结点,称为根结点,根结点没有前驱结点。

2、除根结点,其余的结点被分为M(M>0)个互不相交的集合,其中每个集合其又是一棵结构与树类似的子树,每棵子树的根结点有且只有一个前驱,其可以有0个或者多个后继。所以树是递归定义的。

如上图所示,树的结构其倒过来就和我们现实生活中的树长得很像了。

要注意的是,树形结构中,我们的子树之间是不能有交集的。

下面为树的几个要求:

1、子树之间是不相交的(如果相交那么就是另外一种数据结构图了)

2、除了根结点外,每个结点有且仅有一个父节点,即前驱结点有且仅有一个。

3、一颗有N个结点的树,其边有N-1条。

 树的相关术语:

父结点: 若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点;如上图:A是B的⽗ 结点

子结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点;如上图:B是A的孩⼦结点 

结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;⽐如A的度为6,F的度为2,K的度为0

树的度:一颗树中,最大的结点的度就是这个树的度,如上图,结点的度最大的是A为6,那么树的度就为6。

叶子节点:度为0的结点就为叶子结点,如上图,B、C、H、I、J、P、Q、K、L、M、N就为叶子结点。

分支结点:度不为0的结点

结点的层次:从根的开始定义起,根为第1层、以此类推

树的高度或深度:树中结点的最大层次。如上图为4 

结点的祖先:根结点。如上就是A结点

路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;⽐如A到Q的路径为: A-E-J-Q;H到Q的路径H-D-A-E-J-Q

子孙:以某结点为根的子树中任一结点都称为该结点的子孙。

森林:由m(m>0)棵互不相交的树的集合称为森林

树的表示:

前面我们已经知道我们的树是咋样的情况了,那么我们在代码中要如何进行表示一个树结构呢?

在程序中我们表示树的方式有很多种,我们要根据使用场景来选择合适的表示方式,常见的表示方法有:孩子表示法,孩子兄弟表示法,双亲表示法。

下面是我们的孩子兄弟表示法:

孩子兄弟表示法,就是两个指针,一个指针指向其左孩子,一个指针指向其右边的第一个兄弟。

树在实际运用:

实际上我们早已在电脑上使用过树结构了,我们计算机上的文件存储和管理文件的结构,其就是使用的树形结构来组织和管理文件和文件夹的。在文件系统中,树结构被广泛应用,通过父结点,层层的往下找其子结点,然后找到最终的文件。其通过父结点和子结点之间的关系来表示不同的层级之间的文件和上一层文件夹之间的关系。

二、二叉树 

二叉树的概念和结构:

二叉树是树形结构中的一种特殊情况,也是我们最常用的一种树形结构,一颗二叉树是结点的一个有限集合,该集合由一个根结点再加上两棵分别称为左子树和右子树的二叉树组成,或者为空。

如下:

在上面的图中我们可以看到二叉树的特点:

1、二叉树不存在度大于2的结点

2、二叉树的子树是有左右之分的,次序是不能颠倒的,所以二叉树是有序树

二叉树会有下面几种情况:

特殊的二叉树:

1、满二叉树

一个二叉树,如果其每一层的结点树都达到最大值,那么这个二叉树就是满二叉树。即:我们现在有一个层数为k的二叉树,那么我们的结点数,为2的k次方-1的时候,那么我们的二叉树就是满二叉树。

如下:

2、完全二叉树

完全二叉树,也是一种特殊的二叉树,它的定义是 在二叉树的前提下,其除了最后一层外,其余的层的结点都是满的,而且最后一层的结点都是集中在左侧。

如下:

二叉树的性质:

1、若规定根结点的层次为1,则一颗树非空二叉树的第i层上最多的结点个数为2的i次方-1个结点

2、若规定根结点 的层次为1,则一棵深度为h的二叉树的最多的结点数为2的h次方-1个结点

3、若规定根结点的层次为1 ,具有n个结点的满二叉树的深度h=log2(n+1)

二叉树的存储结构:

二叉树一般使用两种结构存储吗,一种顺序结构,一种是链式结构。

顺序存储:

顺序存储结构底层上是使用数组来存储,不过一般使用数组存储的话就是满二叉树,因为完全二叉树使用数组存储,这是因为不是完全二叉树的话,其会造成空间的浪费。

如下所示:

不过实际上我们通常将堆(二叉树的一种)使用顺序结构的数组来进行存储,不过要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两个回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

链式存储:
二叉树的链式存储通过链表形式动态的进行表示结点间的逻辑关系,其方法如下:

通常的⽅法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩⼦所在的链结点的存储地址。链式结构⼜分为⼆叉链和三叉链,当前我们学习中⼀般都是⼆叉链。后⾯课程学到⾼阶数据结构如红⿊树等会⽤到三叉链。

其具体思路如下:

1、结点结构:

其有三个成员组成:

数据域:存储当前结点的元素值

左指针域:指向左子结点的地址

右指针域:指向右子结点的地址

2、链式类型划分:

二叉链:仅含左右子结点指针

               空间效率高,满足基础算法实现需求

三叉链:增加父结点指针域

               便于逆向溯源,应用于红黑树等复杂数据结构

三、实现顺序结构二叉树

 堆的概念和结构:

如果有⼀个关键码的集合K  = {k0 ,k1, k2, ...,kn−1 },把它的所有元素按完全⼆叉树的顺序存储⽅式存储,在⼀个⼀维数组中,并满⾜:Ki<=  K(2i+1)

(K >=K(2*i+1) 且Ki<=  K (2*i+2))i = 0、1、2...,则称为⼩堆(或⼤堆)。将根结点最⼤的堆叫做最⼤堆或⼤根堆,根结点最⼩的堆叫做最⼩堆或⼩根堆。

如下:

堆的性质:

1、堆中的某个结点的值总是不大于或者不小于其父结点

2、堆总是一棵完全二叉树

二叉树的一些特点:

对于具有n个结点的完全二叉树,如果按照从上到下,从左至右的顺序,对所有的结点从0开始进行编号,那么对于编号为i的结点有下面的几个性质:

1、若i>0,i位置的父结点序号:(i-1)/2;i=0的话,那么其是根结点 ,没有父结点

2、若2i+1<n,那么左孩子序号为2i+1,如果2i+1>=n,那么没有左孩子

3、若2i+2<n,那么其右孩子序号为2i+2,如果2i+2>=n那么没有右孩子

堆的实现:

前面我们已经了解了啥是堆,堆的结构是如何的,那么我们下面就通过代码来实现堆的功能。

首先我们要创建一个堆结构,那么我们该如何进行表示呢?通过上面的学习我们知道,堆是顺序存放的,那么我们堆的实现的底层还是使用数组来实现。

然后就是简单的初始化:

那么我们的堆如何进行插入数据呢?

我们会选择在尾部进行插入,我们插入后,如何将当前的二叉树变成堆的结构,我们的堆是有序的,其子结点要不就是大于或者等于其父结点,要不就小于或者等于其父结点,所以我们插入尾部后,我们还需要对这个二叉树进行调整,那么我们的堆如果是小堆,那么我们小的元素就要往上存放,父结点一定要小于子结点,所以我们可以通过当前结点找到其父结点,然后进行比较,如果新插入的结点比其父结点要小,那么新插入的结点和父结点就进行交换。如果是大堆的话,那么就还是一样,大的往上走即可。这种方法我们叫做向上调整法。

代码如下:

上面我们完成了入堆的操作,那么我们接下来就完成对于堆的数据的删除,那么我们要从那里删除呢?我们堆的删除,就是删除的堆顶的元素,那么我们删除堆顶元素要如何进行删除呢?

如果我们是直接进行删除,那么我们就会发现,我们整个树的结构都会发生改变,我们当前数组的元素的下标都会直接往前移动一个位置。那么我们后续再进行处理就会变得很麻烦,那么我们要如何进行处理呢?

我们可以将堆顶的元素和堆尾的元素进行交换,然后直接尾删即可,然后我们再对堆顶的元素进行向下调整,即将这个数据和其子结点进行比较,如果是大堆的话,那么就是谁大,谁往上放,反之如果是小堆,那么谁小谁往上放。

代码如下:

 那么上面就是我们的堆的基本功能的实现。

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

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

相关文章

linux有效裁剪视频的方式(基于ffmpeg,不改变分辨率,帧率,视频质量,不需要三方软件)

就是在Linux上使用OBS Studio录制一个讲座或者其他视频&#xff0c;可能总有些时候会多录制一段时间&#xff0c;但是如果使用剪映或者PR这样的工具在导出的时候总需要烦恼导出的格式和参数&#xff0c;比如剪映就不支持mkv格式的导出&#xff0c;导出成mp4格式的视频就会变得很…

SystemVerilog—Interface语法(一)

SystemVerilog中的接口&#xff08;interface&#xff09;是一种用于封装多模块间通信信号和协议的复合结构&#xff0c;可显著提升代码复用性和维护效率。其核心语法和功能如下&#xff1a; 一、接口的基本定义 1. 声明语法 接口通过interface关键字定义&#xff0c;支持信…

android binder(四)binder驱动详解

ref&#xff1a; Android10.0 Binder通信原理(五)-Binder驱动分析_binder: 1203:1453 ioctl 40046210 77004d93f4 return-CSDN博客 https://juejin.cn/post/7214342319347712057#heading-0 第6课第1节_Binder系统_驱动情景分析_数据结构_哔哩哔哩_bilibili

QT/c++航空返修数据智能分析系统

简介 1、区分普通用户和管理员 2、界面精美 3、功能丰富 4、使用cppjieba分词分析数据 5、支持数据导入导出 6、echarts展示图表 效果展示 演示链接 源码获取 int main(){ //非白嫖 printf("&#x1f4e1;:%S","joyfelic"); return 0; }

ToolsSet之:数值提取及批处理

ToolsSet是微软商店中的一款包含数十种实用工具数百种细分功能的工具集合应用&#xff0c;应用基本功能介绍可以查看以下文章&#xff1a; Windows应用ToolsSet介绍https://blog.csdn.net/BinField/article/details/145898264 ToolsSet中Number菜单下的Numeric Batch是一个数…

Ubuntu20.04 LTS 升级Ubuntu22.04LTS 依赖错误 系统崩溃重装 Ubuntu22.04 LTS

服务器系统为PowerEdge R740 BIOS Version 2.10.2 DELL EMC 1、关机 开机时连续按键盘F2 2、System Setup选择第一个 System BIOS 3、System BIOS Setting 选择 Boot Setting 4、System BIOS Setting-Boot Setting 选择 BIOS Boot Settings 5、重启 开启时连续按键盘F11 …

(javaSE)Java数组进阶:数组初始化 数组访问 数组中的jvm 空指针异常

数组的基础 什么是数组呢? 数组指的是一种容器,可以用来存储同种数据类型的多个值 数组的初始化 初始化&#xff1a;就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。 数组初始化的两种方式&#xff1a;静态初始化&#xff0c;动态初始化 数组的静态初始化 初始化…

支持向量机(SVM)例题

对于图中所示的线性可分的20个样本数据&#xff0c;利用支持向量机进行预测分类&#xff0c;有三个支持向量 A ( 0 , 2 ) A\left(0, 2\right) A(0,2)、 B ( 2 , 0 ) B\left(2, 0\right) B(2,0) 和 C ( − 1 , − 1 ) C\left(-1, -1\right) C(−1,−1)。 求支持向量机分类器的线…

UE特效Niagara性能分析

开启Niagara调试器 开启显示概览 界面显示 &#x1f7e9; 上方绿色面板&#xff1a;Niagara DebugHud 这是 HUD&#xff08;调试视图&#xff09; 模式下的性能统计显示&#xff0c;内容如下&#xff1a; 项目含义SystemFilter: ShockWave_01当前选中的 Niagara 粒子系统名称…

碳中和新路径:铁电液晶屏如何破解高性能与节能矛盾?

一、显示技术困局&#xff1a;当 “高刷” 遭遇 “高耗” 在元宇宙、电竞产业蓬勃发展的当下&#xff0c;显示设备的刷新率与能耗成为行业痛点。传统液晶受 “边缘场效应” 制约&#xff0c;刷新率长期停滞在 300Hz 以下&#xff0c;动态画面拖影问题显著&#xff1b;同时&…

Vue3+SpringBoot全栈开发:从零实现增删改查与分页功能

前言 在现代化Web应用开发中&#xff0c;前后端分离架构已成为主流。本文将详细介绍如何使用Vue3作为前端框架&#xff0c;SpringBoot作为后端框架&#xff0c;实现一套完整的增删改查(CRUD)功能&#xff0c;包含分页查询、条件筛选等企业级特性。 技术栈介绍 前端&#xff1…

IBM 与嘉士伯(Carlsberg)携手推进 SAP S/4HANA 数字化转型,打造啤酒行业新范式

在啤酒酿造拥有悠久传统的同时&#xff0c;嘉士伯也在积极拥抱前沿技术&#xff0c;迈出数字化转型的坚实步伐。2025年&#xff0c;嘉士伯宣布与 IBM 建立多年的合作伙伴关系&#xff0c;在其西欧业务中全面部署 SAP S/4HANA&#xff0c;旨在提升企业的运营效率、敏捷性和创新能…

深度解析 Nginx 配置:从性能优化到 HTTPS 安全实践

引言 Nginx 作为高性能的 Web 服务器和反向代理&#xff0c;其配置灵活性和强大功能备受开发者青睐。本文基于一份生产环境的 Nginx 配置文件&#xff0c;详细拆解其核心配置逻辑&#xff0c;涵盖性能优化、HTTPS 安全配置、反向代理及静态资源处理等关键环节&#xff0c;帮助…

传送文件利器wormhole的使用方法

传送文件利器wormhole的使用方法 wormhole文件传送工具是基于python的一个快捷的传送工具&#xff0c;在安装此工具之前首先要部署好python环境。 安装的过程如下&#xff1a; 1.部署好python 环境 LINUX系统自带PYTHON环境&#xff0c;直接安装即可。 WINDOWS系统需要安装py…

LangChain输出格式化实践:提升测试工程师LLM开发效率的完整指南

引言 在基于LangChain的LLM测试开发中&#xff0c;输出格式化是连接大模型推理能力与自动化测试系统的关键环节。通过结构化输出&#xff08;如JSON&#xff09;&#xff0c;测试工程师可快速将LLM生成的测试用例、缺陷报告等结果对接至CI/CD流水线。本文系统解析LangChain内置…

Go 语言 + Word 文档模板:WordZero 引擎如何让企业文档处理效率提升 300%?

前言 在企业级应用开发中&#xff0c;自动化生成Word文档一直是个令人头疼的需求。传统的方案要么依赖于复杂的Office COM组件&#xff0c;要么使用功能有限的第三方库。今天为大家介绍一个纯Go语言实现的Word操作库——WordZero&#xff0c;特别是其强大的模板引擎功能&#…

Eclipse 修改字符集

Eclipse 修改字符集 在软件开发过程中,字符集的设置对于代码的正确显示和运行至关重要。Eclipse 作为一款流行的集成开发环境(IDE),提供了方便的字符集修改功能。本文将详细讲解如何在 Eclipse 中修改字符集,以确保项目文件的正确处理。 1. 引言 在 Java 开发中,常见的…

C++ 游戏开发详细流程

&#x1f9e0; 第一阶段&#xff1a;项目规划与架构设计 关键词&#xff1a;系统性、模块化、可扩展性 1.1 目标明确 游戏类型&#xff1a;2D / 2.5D / 3D / VR平台选择&#xff1a;PC、主机、移动设备多人/单人&#xff1a;是否含网络模块&#xff08;决定是否使用 socket、U…

使用Docker-NVIDIA-GPU开发配置:解决 Docker NVIDIA 运行时错误方法

问题描述 运行 Docker 命令时,系统提示 docker: Error response from daemon: unknown or invalid runtime name: nvidia,表明 Docker 无法识别 NVIDIA 运行时。这一错误通常出现在使用 --runtime=nvidia 和 --gpus 参数时,意味着 NVIDIA 容器运行时未正确安装或配置。NVID…

3516cv610在sample_aiisp上多创一路编码流,方法

3516cv610在sample_aiisp上多创一路编码流&#xff0c;方法 首先确保 vpss grp0有视频流 最好保证 已经有一路视频流能推出来 多创一路编码流思路为 将 vpss grp0又绑定给 vpss_chn1 vpss_chn1有绑定给 venc_chn1 这样我们就多创了一路视频流。 这里思路完全正确 可以实现…