说说BTree和B+Tree

news2025/1/19 3:45:59

分析&回答

B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引。B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉树演化而来的。
接下来我们一步步了解 二叉查找树 > 平衡二叉树(AVLTree) > 平衡多路查找树(B-Tree) > B+树。

二叉查找树

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

要想效率高,平衡不可少。所以我们需要平衡二叉树,或称AVL树。

平衡二叉树(AVLTree)

平衡二叉树(AVL树)在符合二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为1。下面的两张图片,左边是AVL树,它的任何节点的两个子树的高度差<=1;右边的不是AVL树,其根节点的左子树高度为3,而右子树高度为1; 

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

这四种失去平衡的姿态都有各自的定义: 

  1. LL:LeftLeft,也称“左左”。插入或删除一个节点后,根节点的左孩子(Left Child)的左孩子(Left Child)还有非空节点,导致根节点的左子树高度比右子树高度高2,AVL树失去平衡。
  2. RR:RightRight,也称“右右”。插入或删除一个节点后,根节点的右孩子(Right Child)的右孩子(Right Child)还有非空节点,导致根节点的右子树高度比左子树高度高2,AVL树失去平衡。
  3. LR:LeftRight,也称“左右”。插入或删除一个节点后,根节点的左孩子(Left Child)的右孩子(Right Child)还有非空节点,导致根节点的左子树高度比右子树高度高2,AVL树失去平衡。
  4. RL:RightLeft,也称“右左”。插入或删除一个节点后,根节点的右孩子(Right Child)的左孩子(Left Child)还有非空节点,导致根节点的右子树高度比左子树高度高2,AVL树失去平衡。 AVL树失去平衡之后,可以通过旋转使其恢复平衡。

平衡多路查找树(B-Tree)

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

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

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+树

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的高度一般都在2 ~ 4层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1 ~ 3次磁盘I/O操作。

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

反思&扩展

平衡多路查找树恢复平衡

下面分别介绍四种失去平衡的情况下对应的旋转方法。

LL的旋转。LL失去平衡的情况下,可以通过一次旋转让AVL树恢复平衡。步骤如下:

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

LL旋转示意图如下: 

RR的旋转:RR失去平衡的情况下,旋转方法与LL旋转对称,步骤如下:

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

RR旋转示意图如下: 

LR的旋转:LR失去平衡的情况下,需要进行两次旋转,步骤如下:

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

LR的旋转示意图如下: 

RL的旋转:RL失去平衡的情况下也需要进行两次旋转,旋转方法与LR旋转对称,步骤如下:

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

RL的旋转示意图如下:

喵呜面试助手:一站式解决面试问题,你可以搜索微信小程序 [喵呜面试助手] 或关注 [喵呜刷题] -> 面试助手 免费刷题。如有好的面试知识或技巧期待您的共享!

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

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

相关文章

第二证券:股吧沸腾!AI算力新龙头来了?

9月6日晚间&#xff0c;中贝通讯披露公告&#xff0c;公司与青海联通签定算力服务结构协议&#xff0c;青海联通拟向中贝通讯批量收买AI算力服务&#xff0c;服务费总金额为3.46亿元&#xff08;含税&#xff09;。 到9月6日&#xff0c;中贝通讯报27.58元/股&#xff0c;最新…

正中优配:国内怎么买美股?

近年来&#xff0c;随着我国经济的发展和对全球金融市场的越来越深入的了解&#xff0c;越来越多的投资者开始重视美国股市。而想要在国内购买美国股票并不是一件简单的事情&#xff0c;本文将从多个视点进行剖析。 一、注册海外买卖账户 在国内购买美股的条件是需求注册海外买…

Spring boot环境搭建

使用IDE工具&#xff1a;IntelliJ IDEA 目录 一、安装JAVA 二、安装maven&#xff08;Java项目管理工具&#xff09; 三、安装IDE 四、在IDE中配置spring boot项目环境 1、配置jdk 2、配置maven 3、安装创建spring boot项目插件&#xff1a;Spring Assistant 4、安装简…

使用Smartctl脚本输入当前所有磁盘的状态

一、安装Smartctl yum install smartmontools 二、写一个脚本输出当前所有磁盘的状态并且按名称分别写入到文件中 #!/bin/bashfor dev in $(lsblk -l | grep disk | awk {print $1}) doecho "检测磁盘 $dev"smartctl -a /dev/$dev > $dev.smartctl done 以下是这…

基于SpringBoot+thymeleaf的物资管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 这是一个物资管理系统…

【校招VIP】产品群面角色之闪光者

考点介绍&#xff1a; 闪光者在群面中要注意&#xff0c;在别人表述的时候需要找关键点&#xff0c;听到与之契合的要点时&#xff0c;审时度势的插入战局给予贡献性意见。 产品群面角色之闪光者-相关题目及解析内容可点击文章末尾链接查看&#xff01;一、考点题目 1. 一个产…

typeScript学习笔记(一)

学习资源来自&#xff1a; 类与接口 TypeScript 入门教程 (xcatliu.com) 一.TypeScript的安装和运行 1.安装TypeScript 通过npm&#xff08;Node.js包管理器&#xff09;安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了Ty…

长胜证券:资本市场的含义是什么?

本钱商场是指企业和政府通过证券生意来筹集资金并进行出资活动的商场。本钱商场通常被分为两个部分&#xff1a;初级商场和二级商场。初级商场是新证券发行的商场&#xff0c;而二级商场则是已发行证券的生意商场。本钱商场的展开程度是一个国家经济展开的重要目标之一。 从宏…

智能时代的蜕变:人工智能发展历程

原创 | 文 BFT机器人 前沿 2022年底&#xff0c;一款名为ChatGPT的人工智能聊天应用引起了巨大轰动&#xff0c;迅速火遍互联网。与传统的聊天机器人不同&#xff0c;ChatGPT更像是一位能够理解人类的虚拟智能助手&#xff0c;它具备智能推断和学习的能力&#xff0c;能够与用…

长胜证券:主板或以震荡整理为主 结构性行情持续

长胜证券指出&#xff0c;技术面看&#xff0c;沪指3150点上方谨慎看多&#xff0c;缩量横盘整理代表强势&#xff0c;向上打破需市场放量且权重配合&#xff0c;后市若打破并站稳3230点可视为强势回转行情开启&#xff0c;考虑到短期人民币弱势格局&#xff0c;主板或以震动整…

京东方只有一个“王东升”,但需要更多“陈炎顺”

文&#xff5c;新熔财经 作者&#xff5c;谢逊 20多年前&#xff0c;京东方手握30亿元的巨额资产&#xff0c;站在企业发展的十字路口踌躇。 有人建议&#xff0c;买望京的地&#xff0c;进军房地产。 如果真是这样干了&#xff0c;那么今天的京东方应该会是一个吃喝不愁、…

el-tree 懒加载数据,展开的节点与查询条件联动

目录 效果描述实现原理步骤1&#xff1a;el-tree设置node-key步骤2&#xff1a;懒加载时对数据进行处理&#xff0c;给整个树形数据添加唯一值步骤3&#xff1a;(联动) 点击左侧树形结构&#xff0c;右侧对应查询框自动赋值步骤4&#xff1a;(联动) 右侧查询条件选择好后&#…

AWS实例上本地部署ChatGLM2-6B

此篇博客主要介绍如何在AWS上创建带GPU的instance&#xff0c;并在instance上部署ChatGLM大模型。 AWS上申请带GPU的instance ChatGLM虽然也支持在CPU的instance上部署&#xff0c;但这里选择在GPU的instance上部署。所以&#xff0c;先在AWS上选择带GPU的instance。AWS上区分…

Python八连冠!它的资本到底是什么?带你详解Python的牛逼之处

Python 连续八年名列前茅 根据榜单显示&#xff0c;Python 不仅在“Spectrum”综合排名中保持第一的位置&#xff0c;而且远超第二名 Java。 对此&#xff0c;IEEE Spectrum 在发布编程语言榜单时写道&#xff0c;Python 主导地位的增强似乎在很大程度上是以牺牲较小、更专业…

华为云API人脸识别服务FRS的感知力—偷偷藏不住的你

云服务、API、SDK&#xff0c;调试&#xff0c;查看&#xff0c;我都行 阅读短文您可以学习到&#xff1a;人工智能AI人脸的识别、检测、搜索、比对 1、IntelliJ IDEA 之API插件介绍 API插件支持 VS Code IDE、IntelliJ IDEA等平台、以及华为云自研 CodeArts IDE&#xff0c;…

发送信息到我的眼镜上

很久很久以前&#xff0c;购得一个Vufine单目眼镜显示器&#xff0c;最近又拿它来折腾。 通过Pi4的连接&#xff0c;现在可以让任意的网友发送图文到眼镜上。 当然更理想的是通过PiZero2W再加上一个电源即可移动使用。 这里讲了实现的代码&#xff0c;总体也不太复杂。 发送…

ChatGLM2_6b安装

Chatglm2_6b安装 一、安装要求 1、硬件 能否使用,或者以什么模式使用主要取决于显卡的显存 2、能否使用AMD显卡? 可以,甚至可以使用CPU,但是需要降低精度。 以CPU模式运行大概需要32GB 内存。 二:工程与下载 官方路径工程路径: 一代工程: https://github.com/TH…

期权的具体操作步骤详解(期权盈利技巧)

做期权买卖首先我们要清楚在期权中有四个交易方向,分别是期权买方&#xff1a;认购做多&#xff0c;认沽做空&#xff0c;两者互为对手方&#xff0c;期权卖方&#xff0c;卖认购做空&#xff0c;卖认沽做多&#xff0c;只要我们明白了期权的方向即可判断做出选择&#xff0c;下…

算法 数据结构 斐波那契数列 递归实现斐波那契数列 斐波那契递归的优化 斐波那契数列递归求解 多路递归实现 斐波那契算法系列 数据结构(十一)

1. 什么是斐波那契数列&#xff1a; 之前的例子是每个递归函数只包含一个自身的调用&#xff0c;这称之为 single recursion 如果每个递归函数例包含多个自身调用&#xff0c;称之为 multi recursion 递推关系 下面的表格列出了数列的前几项 F0F1F2F3F4F5F6F7F8F9F10F11F12…

空气传导耳机哪个牌子好?市面上热销火爆的气传导耳机推荐

​传统入耳式耳机佩戴着容易滑落&#xff0c;戴不稳&#xff0c;久戴耳朵酸痛等问题&#xff0c;气传导耳机的出现就避免了这些问题的发生&#xff0c;我来推荐几款市面上热销火爆且使用感不错的气传导耳机给到大家&#xff0c;来看看吧&#xff01; 推荐1&#xff1a;NANK南卡…