数据结构:二叉查找树,平衡二叉树AVLTree,红黑树RBTree,平衡多路查找数B-Tree,B+Tree

二叉查找树

二叉树具有以下性质:左子树的键值小于根的键值,右子树的键值大于根的键值。

在这里插入图片描述

对该二叉树的节点进行查找发现深度为1的节点的查找次数为1,深度为2的查找次数为2,深度为n的节点的查找次数为n,因此其平均查找次数为 (1+2+2+3+3+3) / 6 = 2.3次。

平衡二叉树AVLT

为了提高二叉树的查找效率,显然二叉树层级越少越好,于是就有了平衡二叉树。它在符合二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为1,如下图所示:

在这里插入图片描述

AVL二叉树的高度为:
l o g 2 n log_2n log2n
如果在AVL树中进行插入或删除节点,可能导致AVL树失去平衡,这种失去平衡的二叉树可以概括为四种姿态:LL(左左)、RR(右右)、LR(左右)、RL(右左)。它们的示意图如下:

在这里插入图片描述

AVL树失去平衡之后,可以通过旋转使其恢复平衡。下面分别介绍四种失去平衡的情况下对应的旋转方法。

LL的旋转:

  1. 将根节点的左孩子作为新根节点。
  2. 将新根节点的右孩子作为原根节点的左孩子。
  3. 将原根节点作为新根节点的右孩子。

在这里插入图片描述

RR的旋转:

  1. 将根节点的右孩子作为新根节点。
  2. 将新根节点的左孩子作为原根节点的右孩子。
  3. 将原根节点作为新根节点的左孩子。

在这里插入图片描述

LR的旋转:

  1. 围绕根节点的左孩子进行RR旋转。
  2. 围绕根节点进行LL旋转。

在这里插入图片描述

RL的旋转:

  1. 围绕根节点的右孩子进行LL旋转。
  2. 围绕根节点进行RR旋转。

在这里插入图片描述

红黑树 RBT

因为二叉搜索树有可能会出现极端的情况,就是只有一侧有数据,那这样的话就会降级为链表。后来出现了平衡二叉树,但是由于强制平衡所导致付出的代价比较高昂,所以红黑树出现了。

红黑树(Red Black Tree) 的实现是基于二叉查找树的,对于含有n个节点的二叉查找树的最坏的情况是这n个节点形成一条单链,此时二叉查找树的高度为n,时间复杂度为O(n)。为了维持AVL的高度,就需要采取一些措施在不影响二叉查找树的性质下改变二叉查找树的结构,使之平衡。红黑树就是这样一种二叉查找树,即自平衡二叉查找树,也就是红黑树。

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。

  1. 根节点是黑色
  2. 所有叶子都是黑色,叶子是NUIL节点。
  3. 红色节点的两个子节点都是黑色
  4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点,这一点就要求,如果一个分支比另一个分支多了一层,那么就必须多一个红色节点。

在这里插入图片描述

当对红黑树进行插入或删除时,就有可能破坏红黑树的性质,这时需要通过变色、左旋与右旋操作平衡红黑树。变色操作很简单,红变黑,黑变红;左旋可以看成是在某个区域内沿着某个节点X逆时针旋转,右旋是顺时针。然后X就成了此区域内的最高节点。

在这里插入图片描述

红黑树并没有像AVL那样对树的平衡有那么严格的要求,它追求的是大致平衡,因此左旋右旋操作没那么频繁。它的高度最多是
2 ∗ l o g 2 ( n + 1 ) 2 * log_2(n+1) 2log2(n+1)
因此时间复杂度也是这个,其查找效率虽然不如AVL,但是还是处于同一量级的。

AVL适合查多改少的场景;红黑树相较于AVL,更适合频繁插入或删除的场景。

在插入节点时,先将其设置为红色(满足特性4),然后特性1和2好说,所以需要重点考虑的是特性3,然后再做一些旋转和改色。

在整个插入旋转的过程中,我们一定要确保高度最低原则,即把红色删除后剩下的高度越低越好,那么在调整的时候能给红色就给红色。

现在新节点为红色,来考虑特性3,如果父节点是黑色,那么无需处理,如果父节点为红色,则需要分情况来处理。此处我们抛开 NULL 节点。并且假设父节点是祖父节点的左节点,实际上父节点是祖父节点的右节点的情况是类似的。

1、新节点为左节点,叔叔节点为红色

2、新节点为左节点,此时必然不存在叔叔节点

3、新节点为右节点,叔叔节点为红色

4、新节点为右节点,此时必然不存在叔叔节点

情况3左旋变成了情况1,情况4通过左旋变成了情况2,因此只需要讨论1,2。

情况1:将祖父节点变为红色,父节点和叔叔节点变为黑色,新增节点是红色,如果祖父节点是根节点那么根节点应该是黑色,如果祖父节点还有父节点,则需要将祖父节点看成输入节点递归向上调整。

情况2:父节点变黑,祖父节点变红,沿父节点右旋。

在这里插入图片描述

平衡多路查找数B-Tree

B-Tree是为磁盘等外存储设备设计的一种平衡查找树。因此在讲B-Tree之前先了解下磁盘的相关知识。

操作系统从磁盘读取数据到内存时是以磁盘(block)为基本单位的(在许多操作系统中,块的大小通常为4k),位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。

InnoDB存储引擎中有(Page)的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K,在MySQL中可通过如下命令查看页的大小:

mysql> show variables like 'innodb_page_size';

而操作系统一个磁盘块的存储空间往往没有这么大,因此InnoDB每次为一个节点申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。而且InnoDB在把磁盘数据读入到内存时也是以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。

B-Tree结构的数据可以让系统高效的找到数据所在的磁盘块。为了描述B-Tree,首先定义一条记录为一个二元组[key, data] ,key为记录的键值,对应表中的主键值,data为一行记录中除主键外的数据。对于不同的记录,key值互不相同。

一棵 m 阶的B-Tree有如下特性

  1. 每个节点最多有 m 个孩子。
  2. 除了根节点和叶子节点外,其它每个节点最少有Ceil(m/2)个孩子。
  3. 若根节点不是叶子节点,则至少有2个孩子 。
  4. 所有叶子节点都在同一层,且不包含其它关键字信息 。
  5. 每个非终端节点包含 n 个关键字信息(P0, P1, …Pn, k1,…kn)
  6. 关键字的个数 n 满足:ceil(m/2)-1 <= n <= m-1
  7. ki(i=1,…n)为关键字,且关键字升序排序。
  8. Pi(i=1,…n)为指向子树根节点的指针。P(i-1)指向的子树的所有节点关键字均小于ki,但都大于k(i-1)

B-Tree中的每个节点根据实际情况可以包含大量的关键字信息和分支,如下图所示为一个 3 阶的B-Tree:

在这里插入图片描述

每个节点为一个页,一个节点上有两个升序排序的关键字和三个指向子节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
  2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。
  3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
  4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。
  5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
  6. 在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点层数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

B+Tree

B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。

从上一节中的B-Tree结构图中可以看到每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

B+Tree相对于B-Tree有几点不同:

  1. 非叶子节点只存储键值信息。
  2. 所有叶子节点之间都有一个链指针。
  3. 数据记录都存放在叶子节点中。

将上一节中的B-Tree优化,由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构如下图所示:

在这里插入图片描述

通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

可能上面例子中只有22条数据记录,看不出B+Tree的优点,下面做一个推算:

InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为10^3)。也就是说一个深度为 3 的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。

实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在24层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要13次磁盘I/O操作。

数据库中的B+Tree索引可以分为聚集索引(clustered index)辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键值。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。mysql数据表都有一个 Primary Key,聚集索引就是基于 Primary Key 创建的,另外你还可以创建其他的索引,就是辅助索引。

InnoDB表中如果不存在 Primary Key ,则MySQL自动生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

MyISAM 引擎使用的也是B+Tree,但是它的叶子节点上存储的data是具体记录的地址,因此被称为非聚集索引

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

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

相关文章

探索移动端可能性:Capacitor5.5.1和vue2在Android studio中精细融合

介绍&#xff1a; 移动应用开发是日益复杂的任务&#xff0c;本文将带领您深入探索如何无缝集成Capacitor5.5.1、Vue2和Android Studio&#xff0c;以加速您的开发流程Capacitor 是一个用于构建跨平台移动应用程序的开源框架。Vue 是一个流行的 JavaScript 框架&#xff0c;用…

无需外接显示器,直接使用windows安装树莓派系统并可远程桌面登录

准备工作: 1.安装树莓派官方烧录工具 raspberry pi imager 2.下载树莓派系统镜像(也可选择在线下载安装) 打开imager工具&#xff0c;选择需要安装包树莓派版本 点击"NEXT"&#xff0c;在弹出的选项中选择编辑设置。 设置登录名和密码&#xff0c;已经所连接的wif…

华大基因助力乌兹别克斯坦精准医学发展,共筑健康丝绸之路

今年上半年&#xff0c;中国与中亚五国元首齐聚陕西西安&#xff0c;举办中国&#xff0d;中亚峰会。过去的20年里&#xff0c;中国已经成为中亚国家的主要投资来源国&#xff0c;总投资额接近400亿美元。乌兹别克斯坦是中国&#xff0d;中亚合作机制的重要参与者&#xff0c;乌…

【100个Cocos实例】东皇太一的技能环绕效果

引言 Cocos中物体围绕物体做圆周运动。 不管是2D还是3D游戏&#xff0c;旋转是游戏中常见的操作之一&#xff0c;它可以用来改变游戏对象的方向、角度或者位置&#xff0c;从而创造出更加生动和有趣的游戏体验。 本文将介绍一下如何实现王者荣耀中东皇太一的技能环绕效果。 …

6S精益管理必备装备降低物料损耗

在工厂生产环境中&#xff0c;设备管理是确保生产效率和质量的关键因素之一。6S管理方法是一种源自日本的管理体系&#xff0c;旨在通过整顿、整理、清扫、清洁、素养、遵守六个步骤&#xff0c;实现工作环境的优化和管理的高效。 仓库管理中&#xff0c;库存损耗一直是企业面…

大模型生态新篇章:以AI Agent为引,助企业创新应用落地

文 | 智能相对论 作者 | 沈浪 以聊天机器人、虚拟助手、智能客服等为代表的对话式人工智能 (Conversational AI Agents ) 在具体服务场景中的应用已经十分普遍。今年以来&#xff0c;随着大模型技术的爆发与加持&#xff0c;对话式AI被市场赋予了更高的期望。 “所有行业都值…

Linux应用开发基础知识——I2C应用编程(十三)

一、无需编写驱动程序即可访问 I2C 设备 APP 访问硬件肯定是需要驱动程序的&#xff0c;对于 I2C 设备&#xff0c;内核提供了驱动程序 drivers/i2c/i2c-dev.c&#xff0c;通过它可以直接使用下面的 I2C 控制器驱动程序来访问 I2C 设备。 i2c-tools 是一套好用的工具&#xff0…

有没有免费可用的亚马逊两步验证器软件?

两步验证&#xff08;Two-Step Verification&#xff09;是一种可以增加账号安全性的有效方式&#xff0c;启用两步验证后&#xff0c;即使你的密码被泄露也不影响&#xff0c;因为除了输入密码外&#xff0c;用户还需要提供二步验证码&#xff0c;通常是通过手机短信、身份验证…

C/C++ 开发SCM服务管理组件

SCM&#xff08;Service Control Manager&#xff09;服务管理器是 Windows 操作系统中的一个关键组件&#xff0c;负责管理系统服务的启动、停止和配置。服务是一种在后台运行的应用程序&#xff0c;可以在系统启动时自动启动&#xff0c;也可以由用户或其他应用程序手动启动。…

免杀原理(php)

免杀原理 0x01 前言 何为免杀&#xff0c;免杀就是一种逃脱杀毒软件查杀的方法&#xff0c;免杀的目的就是绕过“墙”&#xff0c;去执行危险的操作。那么如何绕过这堵“墙”&#xff0c;就是免杀的本质。有句俗话说得好“知己知彼&#xff0c;百战不殆”&#xff0c;想要用好…

JavaScript实现动态背景颜色

JavaScript实现动态背景颜色 前言实现过程HTML实现过程CSS实现过程JS实现过程全部源码 前言 本文主要讲解JavaScript如何实现动态背景颜色&#xff0c;可以根据颜色选择器选择的颜色而实时更新到背景中&#xff0c;如下图所示。 当我们在颜色选择器中改变颜色时&#xff0c;会…