数据结构与算法之 B 树 核心定义 平衡多路搜索树 深度解析

数据结构与算法阿木 发布于 5 天前 2 次阅读


B 树:核心定义与深度解析

B 树是一种平衡的多路搜索树,广泛应用于数据库和文件系统中。它能够有效地组织大量数据,并支持高效的搜索、插入和删除操作。本文将围绕 B 树的核心定义,对其结构、操作和性能进行分析,旨在帮助读者深入理解 B 树的原理和应用。

B 树的核心定义

B 树是一种自平衡的树,它具有以下特点:

1. 多路搜索树:B 树是一种多路搜索树,每个节点可以有多个子节点。

2. 平衡性:B 树保持平衡,即树的高度尽可能小。

3. 节点大小:B 树的节点包含一定数量的键值对,并且每个节点的大小是固定的。

4. 子节点:每个节点可以有多个子节点,但子节点的数量是有限的。

B 树的节点通常包含以下信息:

- 键值对:节点中的键值对用于排序和搜索。

- 子节点指针:指向子节点的指针。

B 树的节点大小和子节点数量由 B 树的阶数(order)决定。阶数是节点中键值对的最大数量,通常表示为 `t`。对于非根节点,键值对的数量在 `t/2` 和 `t-1` 之间。

B 树的结构

B 树的结构可以用以下方式表示:


root


/


/


/


/


/


/


/


/


-------------------


每个节点包含以下部分:

- 键值对:用于排序和搜索。

- 子节点指针:指向子节点的指针。

B 树的节点结构如下:

python

class BTreeNode:


def __init__(self, t, leaf=False):


self.keys = [None] t


self.children = [None] (t + 1)


self.leaf = leaf


self.num_keys = 0

def is_full(self):


return self.num_keys == len(self.keys) - 1


B 树的操作

搜索

B 树的搜索操作类似于二叉搜索树。从根节点开始,根据键值与当前节点的键值进行比较,逐步缩小搜索范围,直到找到目标键值或到达叶子节点。

python

def search(node, key):


if node is None:


return None


if node.leaf:


for i in range(node.num_keys):


if key < node.keys[i]:


return None


if key == node.keys[i]:


return node


return None


else:


for i in range(node.num_keys):


if key < node.keys[i]:


return search(node.children[i], key)


if key == node.keys[i]:


return node


return search(node.children[node.num_keys], key)


插入

B 树的插入操作分为以下步骤:

1. 搜索插入位置:从根节点开始,找到插入位置。

2. 插入键值:将键值插入到节点中。

3. 调整树结构:如果节点已满,则需要分裂节点。

python

def insert_non_full(node, key):


i = node.num_keys - 1


if node.leaf:


while i >= 0 and key < node.keys[i]:


node.keys[i + 1] = node.keys[i]


i -= 1


node.keys[i + 1] = key


node.num_keys += 1


else:


while i >= 0 and key < node.keys[i]:


i -= 1


i += 1


if node.children[i].is_full():


split_child(node, i)


if key > node.keys[i]:


i += 1


insert_non_full(node.children[i], key)

def split_child(node, i):


t = len(node.keys)


y = BTreeNode(t, node.children[i].leaf)


y.num_keys = t // 2


for j in range(t // 2):


y.keys[j] = node.keys[i + 1 + j]


if not node.children[i].leaf:


for j in range(t // 2 + 1):


y.children[j] = node.children[i].children[j + t // 2]


node.keys[i + 1] = y.keys[0]


for j in range(t // 2, t):


node.keys[j] = None


for j in range(t + 1, 2 t):


node.children[j] = None


node.children[i + 1] = y


删除

B 树的删除操作分为以下步骤:

1. 搜索删除位置:从根节点开始,找到删除位置。

2. 删除键值:将键值从节点中删除。

3. 调整树结构:如果删除后节点不满足最小键值对数量,则需要从兄弟节点借键值或合并节点。

python

def delete(node, key):


if node is None:


return


if node.leaf:


delete_leaf(node, key)


else:


delete_non_leaf(node, key)

def delete_leaf(node, key):


i = 0


while i < node.num_keys and key > node.keys[i]:


i += 1


if key == node.keys[i]:


node.keys[i] = None


node.num_keys -= 1


if node.num_keys < len(node.keys) // 2 and (node.parent is None or node.parent.num_keys > len(node.keys) // 2):


return


if node.num_keys < len(node.keys) // 2:


borrow_from_sibling(node, i)


if node.num_keys == 0:


node.parent.children.remove(node)


del node

def delete_non_leaf(node, key):


i = 0


while i < node.num_keys and key > node.keys[i]:


i += 1


if key == node.keys[i]:


delete_key_from_non_leaf(node, i)


else:


delete_from_non_leaf(node, i, key)

def delete_key_from_non_leaf(node, i):


if node.children[i].num_keys >= len(node.keys) // 2:


borrow_from_sibling(node, i)


elif node.children[i + 1].num_keys >= len(node.keys) // 2:


borrow_from_sibling(node, i + 1)


else:


merge_with_sibling(node, i)


delete_key_from_non_leaf(node, i)

def borrow_from_sibling(node, i):


if i == 0:


node.keys[i] = node.children[i].keys[0]


node.children[i].keys[0] = None


node.children[i].num_keys -= 1


node.children[i].keys[node.num_keys // 2] = node.keys[node.num_keys // 2]


node.keys[node.num_keys // 2] = None


elif i == node.num_keys:


node.keys[i - 1] = node.children[i].keys[-1]


node.children[i].keys[-1] = None


node.children[i].num_keys -= 1


node.children[i].keys[node.num_keys // 2] = node.keys[node.num_keys // 2 - 1]


node.keys[node.num_keys // 2 - 1] = None


else:


node.keys[i] = node.children[i].keys[node.num_keys // 2]


node.children[i].keys[node.num_keys // 2] = None


node.children[i].num_keys -= 1


node.children[i].keys[node.num_keys // 2] = node.keys[node.num_keys // 2 - 1]


node.keys[node.num_keys // 2 - 1] = None

def merge_with_sibling(node, i):


if i == 0:


node.children[i].keys.append(node.keys[0])


node.keys[0] = None


node.children[i].keys.extend(node.children[i + 1].keys)


node.children[i].children.extend(node.children[i + 1].children)


node.children[i + 1] = None


node.keys[0] = node.children[i].keys[node.num_keys // 2]


node.keys[1] = None


elif i == node.num_keys:


node.children[i - 1].keys.extend(node.children[i].keys)


node.children[i - 1].children.extend(node.children[i].children)


node.children[i] = None


node.keys[i - 1] = node.children[i - 1].keys[node.num_keys // 2]


node.keys[i - 2] = None


else:


node.children[i - 1].keys.extend(node.children[i].keys)


node.children[i - 1].children.extend(node.children[i].children)


node.children[i] = None


node.keys[i - 1] = node.children[i - 1].keys[node.num_keys // 2]


node.keys[i - 2] = None


B 树的性能分析

B 树的性能主要取决于以下因素:

- 节点大小:节点大小决定了树的高度,从而影响搜索、插入和删除操作的性能。

- 阶数:阶数决定了节点的最大键值对数量,从而影响树的高度和性能。

- 数据分布:数据分布对树的高度和性能有重要影响。

以下是一些性能分析:

- 搜索操作:B 树的搜索操作时间复杂度为 O(log n),其中 n 是树中节点的数量。

- 插入操作:B 树的插入操作时间复杂度也为 O(log n)。

- 删除操作:B 树的删除操作时间复杂度同样为 O(log n)。

总结

B 树是一种平衡的多路搜索树,具有高效的数据组织和管理能力。本文对 B 树的核心定义、结构、操作和性能进行了深入解析,旨在帮助读者更好地理解 B 树的原理和应用。在实际应用中,B 树在数据库和文件系统中发挥着重要作用,为大量数据的存储和管理提供了高效的方法。