当前位置: 首页 > news >正文

B-树(不是B减树)原理剖析(1)

目录

B树的主要特性:

B树的操作:

B树的优点:

为什么要发明出B-树?

B树的概念和原理剖析

原理图讲解(部分讲解在图中)

初始化结点:

处理数据数量计算(了解)

底层代码实现(加深理解)


前些日子我们学了AVl树,红黑树感受到了搜索树在底层和实际应用的广泛和其规则的复杂性,今天我们继续学习一下原理也是搜索树的B-树。

B树是一种自平衡的树数据结构,常用于实现数据库和文件系统的索引。它的设计目的是保持数据有序,并允许高效的插入、删除和搜索操作。B树的特点是它的节点可以包含多个子节点,而不是像二叉树那样每个节点只有两个子节点。这样可以减少树的高度,从而减少查找和更新操作的时间复杂度。

B树的主要特性:

  1. 有序性:B树中的所有节点按升序排列,这使得查找非常高效。每个节点包含一个键值的有序列表,以及指向其子节点的指针。

  2. 多子节点:与二叉树不同,B树中的每个节点可以有多个子节点。节点中的键值和子节点之间有一定的关系:子节点中的值总是介于父节点键值之间。

  3. 平衡性:B树是平衡树,它通过在插入和删除时重新分布节点的键值,确保树的所有叶节点都位于同一层级上。因此,查找的时间复杂度始终为 O(log n),其中 n 是树中的键值总数。

  4. 分支因子:B树的分支因子(通常称为阶数,order)决定了每个节点可以有多少个子节点。一个阶数为 mmm 的 B 树,意味着每个节点最多可以有 m−1m-1m−1 个键和 mmm 个子节点。

  5. 高效磁盘访问:由于每个节点可以存储多个键和指针,B树减少了对磁盘的访问次数。因此,B树在数据库管理系统和文件系统中广泛应用,特别适用于处理大量需要存储在外存(如硬盘)上的数据。

B树的操作:

  • 查找:查找操作从根节点开始,逐层深入,通过比较键值找到目标元素。每次查找时,最多需要访问树的高度层数,这使得查找效率较高。

  • 插入:插入时,首先通过查找找到应插入的位置,然后将新键值插入到合适的节点中。如果节点已满,节点会被拆分,部分键值上移到父节点中。

  • 删除:删除操作更为复杂,如果直接删除某节点会导致树失衡,因此可能需要将相邻节点的键值重新分配,或者将节点合并以保持树的平衡性。

B树的优点:

  • 高效的插入、删除、查找操作,特别是在处理大量数据时。
  • 保证树的高度始终较低,从而减少操作的复杂度。
  • 适用于外存系统的索引结构,因为它减少了对磁盘的访问次数。

常见的改进版本包括 B+(B加)树,它在叶节点中包含所有的数据,并使用顺序链表链接叶节点,从而提高了范围查询的效率。

为什么要发明出B-树?

其实B-树最初被发明出来是为了解决磁盘上读取数据普遍较慢的问题。B-树即使用于内查找也适用于外查找。

这里有人就有意见了呀,为什么别的数据结构不行,偏偏要选择B-呢?

首先,由于磁盘数据过多,假设需要查找磁盘里10亿个值,我们可以看到以上图不同的数据结构的时间复杂度可以看出,最优的就是哈希和平衡二叉树的那两个,AVl树比红黑树相对选择条件更严格,所以选择AVl树,那也需要logn次,也就是说10亿个数据就是30次可以查完,虽然已经很短了,但是磁盘的访问速度太慢了,30次还是显得太多了。

那使用哈希表行不行呢,虽然时间复杂度为o1,但是由于会产生负面的哈希冲突问题,所以比较难以处理多个数据重复映射到同一个位置,比较麻烦!!!

由于磁盘一般不存在空间不足的问题,所以即便使用位图和布隆过滤器也是没有用的。

下面有更清晰的解释可供参考:

所以最大的问题就是磁盘自己本身访问数据太慢了,需要将次数降至个位数才行,于是由于之前的搜索二叉树都是二叉的(一个根最多只有2个孩子节点),所以这里要想提高速率只能降低树的高度,增加根节点的孩子个数(变成多叉)。

就这样B树就诞生了!!!

B树的概念和原理剖析

1970年,R.Bayer和E.mccreight提出了一种适合外查找的树,它是一种平衡的多叉树,称为B树 (后面有一个B的改进版本B+树,然后有些地方的B树写的的是B-树,注意不要误读成"B减树")。一 棵m阶(m>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:

1. 根节点至少有两个孩子//为了增加叉数而设置的

2. 每个分支节点都包含k-1个关键字和k个孩子,其中 ceil(m/2) ≤ k ≤ m ceil是向上取整函数

3. 每个叶子节点都包含k-1个关键字,其中 ceil(m/2) ≤ k ≤ m

4. 所有的叶子节点都在同一层

5. 每个节点中的关键字从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域划 分 6. 每个结点的结构为:(n,A0,K1,A1,K2,A2,… ,Kn,An)其中,Ki(1≤i≤n)为关键 字,且Ki。Ai(0≤i≤n)为指向子树根结点的指针。且Ai所指子树所有结点中的 关键字均小于Ki+1。 n为结点中关键字的个数,满足ceil(m/2)-1≤n≤m-1。

解析开始:我们可以看到这个B树的规则还是比较复杂的。先理清楚几个概念

关键字:就是每一层的节点个数(相当于根)

孩子:就是每个关键字所引出的节点(相当于根的子节点)

2,和3规则可以看出B树是多叉搜索树,如果阶数m为10,那关键字最少为4,最多为9,孩子最少为5,最多为10,并且可以看出,每层的关键字的个数总比其孩子节点少1,说明有一个孩子必定同时是两个相邻的关键字的孩子

第5条规则体现了其仍为搜索树,需要按从大到小排列关键字才可以在后面分裂后通过取中位数的方式取到新的关键字(根)

说到分裂,由于规则3每个叶子节点都包含k-1个关键字,其中 ceil(m/2) ≤ k ≤ m,所以每行的关键字个数最多为阶数-1,当插入的关键字的个数等于阶数m时,就需要进行分裂,分裂具体是怎么样的后面会体现。

原理图讲解(部分讲解在图中)

由于我们这边设的阶数为m = 3,但是我们必须给每行的关键字m个空间,因为如果只给2个(对于m ==3来说,每行关键字最多为2)就无法判断是否关键字等于m,是否需要分裂,因为第3个数无法插入了,多开一个空间方便判断,磁盘很大的不差那一个空间!

刚开始插入时,由于还没有明显的头结点,需要通过不断插入关键字来完成第一次分裂产生,这也比较符合先利用已经开辟好的空间的逻辑

当第一次分裂完成后会产生一个新的单个头节点,之后我们在插入节点的时候必须从叶子节点开始插入,这样才不会剖坏之前已经插入的节点的位置,因为B树仍然是搜索树。从上图也证明了一个结点可能会成为两个根的孩子的理论,所以B树中根节点的个数不是其孩子的两倍,因为根据图可以看出有些孩子被重复利用了,且根节点是通过子节点分裂产生的

分裂引起的根的移动,需要连同着其孩子节点一起移动。种种异样表明B树的设计完全是为了插入数据的方便,不是为了保持平衡而设计的,所以和其他的搜索树不太一样。

这里关键是画图出来,一下展示我画的图:

初始化结点:

根据规则6和演示图解就可以很轻松的得出,每个结点的构造。

由于每个结点是有可能形成多叉的,且一个结点可能会成为两个根的孩子,所以一个结点会先有一个存放关键字的数组,然后为了访问其孩子,还需要一个存有指向此根的全部孩子的指针数组(这里不是单纯的左右指针那么简单了,因为孩子有点多),另外根据上图还需要一个变量n统计关键字的个数(就是当层的结点数),由于我们之前的搜索树都还有一个指向其父亲结点的指针,所以这里也可以考虑加入。

struct BTreeNode
{
    //K _keys[M - 1];
    //BTreeNode<K, M>* _subs[M];

    // 为了方便插入以后再分裂,多给一个空间
    K _keys[M];//关键字(本行节点)
    BTreeNode<K, M>* _subs[M+1];//子节点(快速连串访问,体现树结构)
    BTreeNode<K, M>* _parent;//父亲节点,体现原本三叉链的本质结构
    size_t _n; // 记录实际存储多个关键字 

};

处理数据数量计算(了解)

实际情况运用B树时,阶层通常会很大(B树阶层越大处理的节点数(关键字)就越多数据量就越大),所以我们以下定义形成一个1023阶层的4层的B树。

根据规则,那么每个分支的关键字数最多就为m - 1 = 1023,其孩子为m等于1024,根据下图的逐层推算可以得出每行的关键字和孩子节点的个数。可以看出B树成功的通过压缩了高度同时存储了更多的数据

底层代码实现(加深理解)

欲知后事如何,请听下文分解!!!持续关注博主以解锁B树更多秘密!!!

相关文章:

B-树(不是B减树)原理剖析(1)

目录 B树的主要特性&#xff1a; B树的操作&#xff1a; B树的优点&#xff1a; 为什么要发明出B-树&#xff1f; B树的概念和原理剖析 原理图讲解(部分讲解在图中) 初始化结点&#xff1a; 处理数据数量计算(了解) 底层代码实现(加深理解) 前些日子我们学了AVl树&…...

【shell脚本8】Shell脚本学习--其他

目录 ​编辑 Shell输入输出重定向 重定向深入讲解 Here Document Shell输入输出重定向 Unix 命令默认从标准输入设备(stdin)获取输入&#xff0c;将结果输出到标准输出设备(stdout)显示。一般情况下&#xff0c;标准输入设备就是键盘&#xff0c;标准输出设备就是终端&…...

《深度学习》ResNet残差网络、BN批处理层 结构、原理详解

目录 一、关于ResNet 1、什么是ResNet 2、传统卷积神经网络存在的问题 1&#xff09;梯度消失和梯度爆炸问题 2&#xff09;训练困难 3&#xff09;特征表示能力受限 4&#xff09;模型复杂度和计算负担 3、如何解决 1&#xff09;解决梯度问题 BN层重要步骤&#xff1a; 2…...

javadoc:jdk 9通过javadoc API读取java源码中的注释信息(comment)

几年前写过一博客&#xff1a;《java:通过javadoc API读取java源码中的注释信息(comment)》&#xff0c;简单介绍了通过javadoc API读取源码注释的流程。 那时还是用JDK 1.8。但是在JDK9环境下JDK 1.8的那一套API就不能用了。JDK 9提供了一套新的javadoc API实现注释代码的读取…...

nordic使用FDS保存数据需要注意的地方

FDS使用常见问题 大家在使用FDS模块时,经常碰到的问题有如下几种: FDS不支持掉电保护,所以在Flash操作过程中出现了掉电,FDS行为将未知OTA的时候,新固件的FDS page数目一定要等于老固件的FDS page数,否则将出现不可知行为fds_record_write或者fds_record_update后,强烈…...

docker-compose集群(单机多节点)环境搭建与使用

此方案已经经过生产环境验证&#xff0c;可放心大胆使用如果喜欢&#xff0c;欢迎点赞&#x1f44d;收藏❤️评论噢&#xff5e; 略去 Docker 和 Docker Compose 安装部分,如果有需要的同学&#xff0c;可以评论&#xff0c;创建 docker-compose.yml 文件并配置 Nacos 集群和 M…...

从静态多态、动态多态到虚函数表、虚函数指针

多态&#xff08;Polymorphism&#xff09;是面向对象编程中的一个重要概念&#xff0c;它允许不同类的对象对同一消息做出不同的响应。多态性使得可以使用统一的接口来操作不同类的对象&#xff0c;从而提高了代码的灵活性和可扩展性。 一、多态的表现形式 1. 静态多态&…...

用 Pygame 实现一个乒乓球游戏

用 Pygame 实现一个乒乓球游戏 伸手需要一瞬间&#xff0c;牵手却要很多年&#xff0c;无论你遇见谁&#xff0c;他都是你生命该出现的人&#xff0c;绝非偶然。若无相欠&#xff0c;怎会相见。 引言 在这篇文章中&#xff0c;我将带领大家使用 Pygame 库开发一个简单的乒乓球…...

基于大数据可视化的化妆品推荐及数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…...

Java项目实战II基于Java+Spring Boot+MySQL的汽车销售网站(文档+源码+数据库)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字化时…...

数学基础 -- 微积分最优化之一个最简单的例子

微积分中的一个最简单的最优化例子 问题描述 假设你有一条长度为 10 米的栅栏&#xff0c;你需要围成一个矩形的鸡舍&#xff0c;使得围成的面积最大。求这个矩形的长和宽应是多少&#xff0c;以使得面积最大。 步骤 设定变量&#xff1a; 设矩形的长为 x x x 米&#xff0…...

kubernetes K8S 结合 Istio 实现流量治理

目录 1.Istio介绍&#xff1f; 1.1 Istio是什么&#xff1f; 1.2 Istio流量管理 1.2.1 熔断 1.2.2 超时 1.2.3 重试 2.Istio架构 3.istio组件详解 3.1 Pilot 3.2 Envoy 3.3 Citadel 3.4 Galley 3.5 Ingressgateway 3.5 egressgateway 扩展、k8s1.23及1.23以下版…...

Selenium with Python学习笔记整理(网课+网站持续更新)

本篇是根据学习网站和网课结合自己做的学习笔记&#xff0c;后续会一边学习一边补齐和整理笔记 非常推荐白月黑羽的学习网站&#xff1a; 白月黑羽 (byhy.net) https://selenium-python.readthedocs.io/getting-started.html#simple-usage WEB UI自动化环境配置 (推荐靠谱…...

1.随机事件与概率

第一章 随机时间与概率 1. 随机事件及其运算 1.1 随机现象 ​ 确定性现象&#xff1a;只有一个结果的现象 ​ 确定性现象&#xff1a;结果不止一个&#xff0c;且哪一个结果出现&#xff0c;人们事先并不知道 1.2 样本空间 ​ 样本空间&#xff1a;随机现象的一切可能基本…...

Redis结合Caffeine实现二级缓存:提高应用程序性能

本文将详细介绍如何使用CacheFrontend和Caffeine来实现二级缓存。 1. 简介 CacheFrontend: 是一种用于缓存的前端组件或服务。通俗的讲&#xff1a;该接口可以实现本地缓存与redis自动同步&#xff0c;如果本地缓存&#xff08;JVM级&#xff09;有数据&#xff0c;则直接从本…...

【LLM】Ollama:本地大模型 WebAPI 调用

Ollama 快速部署 安装 Docker&#xff1a;从 Docker 官网 下载并安装。 部署 Ollama&#xff1a; 使用以下命令进行部署&#xff1a; docker run -d -p 11434:11434 --name ollama --restart always ollama/ollama:latest进入容器并下载 qwen2.5:0.5b 模型&#xff1a; 进入 O…...

SpringBoot集成阿里easyexcel(二)Excel监听以及常用工具类

EasyExcel中非常重要的AnalysisEventListener类使用&#xff0c;继承该类并重写invoke、doAfterAllAnalysed&#xff0c;必要时重写onException方法。 Listener 中方法的执行顺序 首先先执行 invokeHeadMap() 读取表头&#xff0c;每一行都读完后&#xff0c;执行 invoke()方法…...

使用ELK Stack进行日志管理和分析:从入门到精通

在现代IT运维中&#xff0c;日志管理和分析是确保系统稳定性和性能的关键环节。ELK Stack&#xff08;Elasticsearch, Logstash, Kibana&#xff09;是一个强大的开源工具集&#xff0c;广泛用于日志收集、存储、分析和可视化。本文将详细介绍如何使用ELK Stack进行日志管理和分…...

前端框架对比与选择

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&#x1f495;&#x1f495;&#x1f495; 目…...

Springboot jPA+thymeleaf实现增删改查

项目结构 pom文件 配置相关依赖&#xff1a; 2.thymeleaf有点类似于jstlel th:href"{url}表示这是一个链接 th:each"user : ${users}"相当于foreach&#xff0c;对user进行循环遍历 th:if进行if条件判断 {变量} 与 ${变量}的区别: 4.配置好application.ym…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...