搜索
您的当前位置:首页正文

数据结构——B-树

来源:易榕旅网

B-树(B-tree)是一种自平衡的多路搜索树,广泛应用于文件系统、数据库系统中,用于存储和查找数据。它的特点是能够高效地支持插入、删除、查找等操作,并且能够在磁盘等外部存储设备中有效地存储大量数据。

B-树的关键特性如下:


1. B-树的基本结构

B-树的每个节点包含以下几个部分:

  • 键值(key):每个节点包含多个键值,并且这些键值是按照升序排列的。
  • 子节点(children):每个节点有多个子节点指针,指向该节点中的子树。

B-树的每个节点有如下特点:

  • 每个节点有 ( m ) 个子节点,其中 ( m ) 被称为阶数,通常是一个预定义的常数。阶数决定了每个节点的最小和最大子节点数。
  • 非根节点至少包含 ( \lceil m/2 \rceil ) 个子节点,根节点可以包含 2 个到 ( m ) 个子节点。
  • 每个节点最多有 ( m-1 ) 个键值

2. B-树的插入和删除

2.1 插入操作

B-树的插入操作遵循以下步骤:

  1. 找到合适的位置:从根节点开始,按照B-树的结构找到合适的位置。
  2. 插入键值:如果找到的节点未满(即包含的键值小于 ( m-1 )),直接插入键值。
  3. 节点分裂:如果节点已满,则进行分裂。分裂后的中间元素上升到父节点,并将新创建的节点作为子节点插入父节点。如果父节点也已满,继续分裂。
2.2 删除操作

B-树的删除操作也遵循一定规则:

  1. 找到删除的元素:首先在树中找到要删除的元素。
  2. 直接删除:如果删除的元素不在叶子节点上,可以通过交换找到该元素的后继或前驱元素来替代删除。
  3. 节点合并或借用:如果删除的元素导致节点的元素少于最小要求,需要通过合并相邻节点或借用兄弟节点的元素来保持B-树的平衡。

3. B-树的实现

我们现在来实现一个简单的B-树,并实现插入操作。

3.1 B-树节点类
class BTreeNode:
    def __init__(self, t, leaf=False):
        self.t = t           # B-树的阶数
        self.leaf = leaf     # 是否是叶子节点
        self.keys = []       # 存储节点的键
        self.children = []   # 存储子节点的指针
3.2 B-树类
class BTree:
    def __init__(self, t):
        self.t = t           # B-树的阶数
        self.root = BTreeNode(t, True)  # 初始化根节点

    # 插入操作
    def insert(self, key):
        root = self.root
        if len(root.keys) == 2 * self.t - 1:  # 根节点已满
            new_node = BTreeNode(self.t, False)
            new_node.children.append(self.root)  # 创建新根节点
            self.split_child(new_node, 0)
            self.root = new_node
        self.insert_non_full(self.root, key)

    # 插入非满节点
    def insert_non_full(self, node, key):
        i = len(node.keys) - 1
        if node.leaf:
            # 插入键值到叶子节点
            while i >= 0 and key < node.keys[i]:
                i -= 1
            node.keys.insert(i + 1, key)
        else:
            # 找到要插入的子节点
            while i >= 0 and key < node.keys[i]:
                i -= 1
            i += 1
            child = node.children[i]
            if len(child.keys) == 2 * self.t - 1:
                self.split_child(node, i)
                if key > node.keys[i]:
                    i += 1
            self.insert_non_full(node.children[i], key)

    # 分裂节点
    def split_child(self, parent, i):
        node = parent.children[i]
        new_node = BTreeNode(self.t, node.leaf)
        parent.keys.insert(i, node.keys[self.t - 1])  # 中间元素上升到父节点
        parent.children.insert(i + 1, new_node)

        new_node.keys = node.keys[self.t:]  # 拷贝后半部分的键值到新节点
        node.keys = node.keys[:self.t - 1]  # 保留前半部分的键值

        if not node.leaf:
            new_node.children = node.children[self.t:]
            node.children = node.children[:self.t]

    # 打印树的内容(层级遍历)
    def print_tree(self, node=None, level=0):
        if node is None:
            node = self.root
        print('Level', level, 'Keys:', node.keys)
        if not node.leaf:
            for child in node.children:
                self.print_tree(child, level + 1)
3.3 使用B-树进行插入操作
if __name__ == "__main__":
    b_tree = BTree(3)  # 创建一个阶数为3的B-树

    # 插入数据
    keys = [10, 20, 5, 6, 12, 30, 7, 17]
    for key in keys:
        b_tree.insert(key)

    # 打印B-树的结构
    b_tree.print_tree()
3.4 输出
Level 0 Keys: [10, 20]
Level 1 Keys: [5, 6]
Level 1 Keys: [12]
Level 1 Keys: [17, 30]

4. 总结

B-树是一种高度自平衡的多路查找树,广泛应用于数据库和文件系统中。通过在每个节点中存储多个键值,B-树可以有效地减少树的高度,从而提高查询效率。通过插入、删除和分裂节点等操作,B-树能够高效地支持大量数据的存储和查找。

在实际应用中,B-树的变种如B+树和B*树也常被使用,尤其在数据库和文件系统中,它们在B-树的基础上做了进一步优化,具有更好的性能。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top