(b5)B-树: 删除

官方信息技术老师·24 页·深入(追求细节与边界)·0 次浏览·2 天前
B-树下溢再平衡删除

B-树的删除操作

看完你能逐情形推导任意删除引发的下溢与再平衡

按 空格/→ 演示下一步

1 / 24 页

全部页面点击任意一页,跳回舞台从这页播放

B-树下溢再平衡删除

B-树的删除操作

看完你能逐情形推导任意删除引发的下溢与再平衡

1第 1 页 · B-树的删除操作

删除的本质挑战

为什么删除比插入更复杂

删除的本质挑战
为什么删除比插入更复杂
2第 2 页 · 删除的本质挑战

删除算法的全局框架

想象整理书柜:你先按书名目录找到位置,抽走它,回头发现那一层书架太空还得重新分发或合并。B-树删除一个关键字,整体就跑着「搜索—删除—修复」三段流程。

搜索定位
从根向下逐节点比较,沿路径定位目标关键字
分类删除
叶节点直接移除;内部节点用前驱或后继替换再删
修复下溢
节点关键字数低于下限,向兄弟借位,失败则合并
整理书柜借走一本书对应 →B-树删除三阶段

按目录定位(搜索)、抽走书(删除)、书架太空借位或合并相邻架(修复)

3第 3 页 · 删除算法的全局框架

删除决策树

三次判断决定走哪条处理路径

图解渲染中…
a2内部节点要先归约为叶子删除a5下界=⌈m/2⌉-1,根节点除外a9合并使父键数-1,可能向上传播
4第 4 页 · 删除决策树

情况一:删除叶子节点

上页决策树的第一步就是「目标在叶子节点」。这是所有情况里最轻松的一种,因为叶子没有孩子要照顾,删除只是从一段有序序列里去掉一个元素。

直接移除键
在叶子节点中找到目标键,从该位置直接删除
检查键数下界
删除后该节点键数 ≥ ⌈m/2⌉−1,否则算「下溢」
满足即终止
未发生下溢则删除完成,整棵树自动合法,无须修复
从书架外侧抽走一本书对应 →叶子节点删除且未下溢

架子够稳就不必动整排,叶够格就不动父节点

underflow    K<m/21\text{underflow} \iff |K| < \lceil m/2 \rceil - 1
5第 5 页 · 情况一:删除叶子节点

情况二:删除内部节点

情况一我们搞定了叶子——直接删就行。但内部节点有左右子树,直接抽掉会让孩子节点悬空。这一页看怎么把它转成叶子再删。

难点所在
内部节点不能直接删,左右子树会失去父节点
替换人选
用右子树最小值(后继)或左子树最大值(前驱)顶替
为何可行
前驱 < 被删键 < 后继,搜索树的大小关系仍成立
降级处理
替换后要删的是叶子,走情况一的删除流程
公司经理换人对应 →内部节点删除

经理岗位不空,由排序紧邻的下属接任,下属原位腾空再清理

6第 6 页 · 情况二:删除内部节点

内部节点删除的三种策略

三条路径做同一件事:找叶子里的键覆盖 k,再走叶子删除。差异只在「去哪儿找」。

图解渲染中…
c1前驱 = 左子树最大键:沿右子节点一路下到叶子c2后继 = 右子树最小键:沿左子节点一路下到叶子c3中序后继 = 在整棵树中找下一个序对应的键,可能跨层
7第 7 页 · 内部节点删除的三种策略

后继节点替换的具体步骤

用右子树最小节点替换原值,再在叶子层把它删掉,分四步走。

1
找后继
在右子树中一路向左,找到最小关键字节点
2
值上提
把后继的关键字值复制到待删的内部节点
3
删后继
在叶子层删除原后继节点的位置
4
修下溢
若后继所在节点关键字不足,按情况一处理
8第 8 页 · 后继节点替换的具体步骤

什么是下溢

前几页我们解决了「删谁」的问题——叶子直接删,内部用后继替换。但真正把关键字拿走后,被波及的节点可能瞬间变薄。薄到什么程度算异常?这就是下溢。

下溢的定义
删除后某节点关键字数低于该阶 B-树所允许的下限
下限公式
m 阶 B-树最少 ⌈m/2⌉−1 个关键字,少于此数即下溢
触发时机
叶子直接删除后,或兄弟已无法借出关键字时
与上溢对称
插入时节点过满称上溢,删除时节点过空称下溢,镜像
指向后续
下溢是触发「借兄弟」或「合并兄弟」算法的入口信号
货架最低库存对应 →节点最少关键字

库存低于下限就算空仓,要么调货要么并仓

kmin=m/21k_{\min}=\lceil m/2\rceil-1
9第 9 页 · 什么是下溢

下溢的边界情况

上页讲到下溢是节点关键字数跌破下限。但根节点是个例外——它是树的'特殊公民',可以比别的节点更少。这条豁免背后,藏着 B-树高度收缩的机制。

普通节点下溢线
除根外,每个节点至少保留 t-1 个关键字
根节点是例外
根允许关键字数少到 1,内部节点甚至可以临时为 0
根空了就降高度
根的唯一关键字被借走或合并走,树高减一
合并穿过根
根仅两子节点合并时,根被替换为合并后的子节点
公司最小编制对应 →B树下溢约束

部门至少留 t-1 人,老板哪怕只剩一人公司也不倒;老板走了,公司缩编一层

10第 10 页 · 下溢的边界情况

旋转:向兄弟借节点

下溢发生后,合并并非唯一选择。当相邻兄弟还有富余时,旋转借一个就能补齐——这是处理下溢代价最小的路径。

触发条件
至少一个兄弟关键字数 > 下限 ⌈m/2⌉−1
选兄弟策略
左右都有富余时优先选右兄弟,更省事
三步旋转
兄弟关键字上移至父节点,父关键字下移填补
保持平衡
三方关键字数都满足下限,根节点不变
O(1) 代价
只调指针,比合并 O(树高) 便宜一个量级
部门之间借调员工对应 →向兄弟节点借节点

兄弟部门出员到经理位=兄弟关键字入父节点;经理下来补人=父关键字下移填补

11第 11 页 · 旋转:向兄弟借节点

左旋与右旋的详细过程

图分两支:右旋向左兄弟借,左旋向右兄弟借。每条路径3步:父key下沉、兄弟key上移、兄弟子树挂载。

图解渲染中…
b1判断兄弟节点是否有富余key可借e1右旋=向左兄弟借,key从左边过来f1左旋=向右兄弟借,key从右边过来e4把借来的子树指针挂到下溢节点
12第 12 页 · 左旋与右旋的详细过程

合并:与兄弟节点合并

当删除后非根节点少于 B-树允许的最少关键码数,且相邻兄弟也没有多余关键码时,借位不再安全,只能把两片节点合成一片,再把父节点中的分隔关键码放下来。

合并条件
节点已下溢,兄弟也仅有 t−1 个关键码,无法借位
合并对象
选择一个相邻兄弟合并;左右均可,取决于当前结构
分隔关键码下移
从父节点取分隔关键码,插入合并节点,连接两侧剩余关键码
合并后容量
若最小度为 t,合并节点恰有 2t−1 个关键码,不超上限
父节点回溯
父节点少一个关键码;若低于下限,继续向上合并或旋转
两节相邻车厢对应 →两个待合并节点

两节都无余位时,父节点的分隔牌放入中间,再合成一节

合并后关键码数=(t1)+1+(t1)=2t1\text{合并后关键码数}=(t-1)+1+(t-1)=2t-1
13第 13 页 · 合并:与兄弟节点合并

合并操作的详细过程

决策入口先判能否旋转,否则进入合并;合并三步走,父节点下溢则递归向上。

图解渲染中…
a1键数低于 ⌈m/2⌉-1 的下溢节点b1判断兄弟能否借出键,能则走上一页讲的旋转c2父子间的分隔键下沉到合并节点中部e1父节点也下溢则向上递归,可能一路传到根
14第 14 页 · 合并操作的详细过程

旋转与合并的抉择条件

从下溢出发,依次问左、右兄弟是否富余,能借则旋,不能借则合。

图解渲染中…
a2富余=键数严格大于下限⌈m/2⌉-1a3右旋:左兄弟→父→当前节点b2左旋:右兄弟→父→当前节点b3合并后从父节点下移一个分隔键
15第 15 页 · 旋转与合并的抉择条件

实例:删除叶子节点

用流程图展示m=3 B-树删除叶子节点且不引发下溢的完整路径,重点观察keys数≥2这一安全判据。

图解渲染中…
a4m=3叶节点最少1key,2key可安全删除b4删后叶子剩1key,正好等于min阈值b5min=ceil(m/2)-1=1,B-树关键下界
16第 16 页 · 实例:删除叶子节点

实例:删除引发旋转修复

流程图:跟踪一棵5阶B树删除键后,从下溢发生到左旋修复的完整步骤。

图解渲染中…
T15阶B树初始状态:最多4键、最少2键;[x,y]表示节点含键x和yT3左子从[10,20]变为[20],键数1<最小值2,触发下溢T4右兄弟[40,50,60]有3键,比最小值2多1个,富余可借T5左旋:父键下移填补下溢节点,兄弟最小键上移补父位
17第 17 页 · 实例:删除引发旋转修复

实例:删除引发合并修复

从叶子下溢开始,跟随流程看无法旋转时如何用合并修复B-树。

图解渲染中…
a5把父节点中夹在两孩子间的分隔键拉下来,作为合并节点的中位键a6新节点内容 = 父键 + 左侧空节点内容 + 右侧兄弟内容a7父节点因送出一个键而变薄,需检查是否继续下溢
18第 18 页 · 实例:删除引发合并修复

实例:删除内部节点

用后继节点替换并触发下溢修复的完整过程

实例:删除内部节点
用后继节点替换并触发下溢修复的完整过程
19第 19 页 · 实例:删除内部节点

实例:连锁下溢修复

沿主路径追踪合并后的连锁反应:从叶子一路传到根。

图解渲染中…
b2判断兄弟关键字数是否大于下限d1父级重新进入借/合判断e2递归终止条件:是否抵达根
20第 20 页 · 实例:连锁下溢修复

插入与删除的对称性

插入与删除的修复看似对称,实则方向相反——一页看清镜像关系

上溢修复(插入)
  • 键数超过上限 m-1
  • 分裂节点,中位键上推
  • 修复向上传递,可连锁
下溢修复(删除)
  • 键数低于下限 ⌈m/2⌉-1
  • 借键旋转 或 合并兄弟
  • 修复向上传递,可连锁
镜像对称:插入遇满用「分裂」,删除遇空用「合并或借键」,均自底向上传
21第 21 页 · 插入与删除的对称性

平衡的代价与收益

B-树删除时要旋转、合并、还可能一路向上连锁修复——这些操作并不便宜。为何不删完先放着,等下次查询时再顺手修?这关系到 B-树的核心设计哲学。

修复代价
每次删除可能引发最多 O(log n) 级联调整,写操作变重
搜索稳定
换来查找永远是 O(log n),不受历史删除影响
延迟诱惑
先标记后整理,听起来能批量处理、写时省事
空间倾斜
标记堆积浪费固定大小的页,树也倾斜,最坏退化为 O(n)
读重抉择
用写时少量代价换读时最强保证,正合数据库胃口
图书馆理架对应 →B-树删除时的主动修复

取下一本就归位——B-树删一个就修一个,写时多费事,读时永远顺手

22第 22 页 · 平衡的代价与收益

核心要点回顾

  • 下溢修复首选旋转,旋转不行才合并
  • 内部节点删除通过后继替换转为叶子删除
  • 下溢可能沿路径向上连锁传播至根
  • 删除是插入的镜像但更复杂
延伸主题:B+树删除的差异惰性删除策略
23第 23 页 · 核心要点回顾

课后思考

先独立思考三分钟,再对照参考答案看自己的思路是否命中要害。

1为什么删除一个键可能触发从叶到根的连锁修复?下溢向上传播的触发条件是什么?

参考答案当兄弟节点也只剩 t-1 个键时,无法借出,只能合并;合并使父节点少一个键,递归向上传播,直到根。

2旋转与合并是下溢修复的两条路径,如何判断哪个代价更小?这个判断会随 t 变化吗?

参考答案优先旋转,因为它保持树高不变、O(1) 完成;仅当兄弟也处于下限才合并(会降低树高)。t 越大,下限越宽松,旋转机会越多。

3如果把 B-树换成 B+ 树,同样的删除逻辑还成立吗?数据只存于叶节点的约束会改变哪些决策?

参考答案基本思路成立,但内部节点的删除不能就地完成,必须用叶节点中的后继替换——所有删除最终都落到叶子上,下溢修复逻辑保持一致。

24第 24 页 · 课后思考