Balance-Tree-Altered

This commit is contained in:
e2hang
2025-08-26 21:39:35 +08:00
parent 3eb93c256c
commit 96738dec6c
19 changed files with 187 additions and 0 deletions

View File

@@ -569,6 +569,142 @@ deleteKey(node, k):
---
✅ 对的,你理解完全正确!我帮你梳理一下:
---
### 在 B-树删除时,如果要删除的关键字 `x->keys[i]` 在**内部节点**
* **前驱predecessor**
* 就是 `x->children[i]` 这个子树中的最大值。
* 为什么?因为 `x->children[i]` 里所有关键字都 **小于** `x->keys[i]`,而前驱就是其中最大的。
* 找法:一路往右孩子走直到叶子,拿到最后一个 key。
* 伪代码:
```cpp
Node<T>* cur = x->children[i];
while (!cur->isLeaf) cur = cur->children.back();
T predecessor = cur->keys.back();
```
* **后继successor**
* 就是 `x->children[i+1]` 这个子树中的最小值。
* 为什么?因为 `x->children[i+1]` 里所有关键字都 **大于** `x->keys[i]`,而后继就是其中最小的。
* 找法:一路往左孩子走直到叶子,拿到第一个 key。
* 伪代码:
```cpp
Node<T>* cur = x->children[i+1];
while (!cur->isLeaf) cur = cur->children.front();
T successor = cur->keys.front();
```
---
### 删除时的策略
* 如果前驱所在子树 `x->children[i]` 有 ≥ t 个 key
* 用前驱替代 `x->keys[i]`,再递归删除前驱。
* 否则如果后继所在子树 `x->children[i+1]` 有 ≥ t 个 key
* 用后继替代 `x->keys[i]`,再递归删除后继。
* 否则(两个子树都只有 t-1 个 key
* 把 `x->keys[i]` 下移到左子树,和右子树合并,再递归删除。
---
📘 **直观理解**
`x->keys[i]` 在父节点,它左边整个子树都比它小,右边整个子树都比它大。
所以前驱就是左子树里最大值,后继就是右子树里最小值。
---
要不要我帮你画一个 **图解例子**(比如 `t=2` 的 B 树,删除一个内部节点的情况),演示「前驱替代」和「后继替代」的区别?
如果你需要,我可以帮你 **写一个完整的 C++ B 树删除函数实现**,直接和你已有的 `BTree` 类整合,并附详细注释。
你希望我帮你写吗?
---
``` html
总结:
1、删除
2、查看是否下溢出
3、下溢出
a.左右节点可以借(大于t - 1)
父亲下来,借的成为父亲
b.不可以借
和兄弟合并
总结得很到位 👍,我帮你整理一下,更系统一些,方便你以后复习 B-树删除算法。
```
---
## 🌳 B-树删除算法总结
### 1. 删除目标
* **在叶子节点找到 key**
👉 直接删除,不涉及复杂调整。
* **在内部节点找到 key**
👉 不能直接删,而是通过 **前驱 / 后继替代** 或 **合并** 来保持 B-树平衡。
---
### 2. 删除步骤总览
1. **删除目标 key**
* 在叶子:直接删。
* 在内部:找前驱或后继替换,再递归删除。
2. **检查是否下溢underflow**
* B-树的每个节点至少要有 `t - 1` 个 key除了根
* 如果某个子节点删除后不足 `t - 1`,则发生下溢。
3. **处理下溢**
* **a. 向兄弟借关键字(兄弟 ≥ t**
* 父节点“下放”一个关键字到下溢的节点,兄弟的关键字“上升”到父节点。
* 保证节点恢复到 ≥ `t - 1`。
* 📌 这是 **旋转rotation** 操作。
* **b. 无法借(兄弟也是 t - 1 → 合并**
* 将下溢节点、父节点中一个关键字、兄弟节点 **合并** 成一个节点。
* 父节点关键字数减少 1。
* 如果父节点变空,整棵树高度减 1根被替换
---
### 3. 前驱 / 后继选择
* **前驱**`x->keys[i]` 的左子树 `x->children[i]` 中的最大值。
* **后继**`x->keys[i]` 的右子树 `x->children[i+1]` 中的最小值。
* 替代规则:
* 左子树有足够关键字(≥ t用前驱替代。
* 否则若右子树有足够关键字(≥ t用后继替代。
* 否则左右子树都不够,执行合并。
---
### 📌 最简总结版(你说的很对)
1. 删除目标 key。
2. 如果节点关键字数 ≥ `t - 1`,不用处理。
3. 如果 < `t - 1`(下溢):
* **能借** → 借兄弟。
* **不能借** → 合并兄弟和父节点关键字。
---
要不要我帮你画一个小例子(`t=2` 的 B-树),演示 **借** 和 **合并** 两种下溢处理,这样你一眼就能看懂?

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB