📜  B树介绍(1)

📅  最后修改于: 2023-12-03 15:29:41.257000             🧑  作者: Mango

B树介绍

B树是一种常用的数据结构,用于在大数据量下进行高效的查找、插入和删除操作。B树的设计目标是减少磁盘I/O次数,因此特别适用于数据存储在磁盘或其他直接存取较慢的媒介上的情况。

B树的定义

B树是一种平衡的多路搜索树。和二叉搜索树不同,B树的一个节点可以有很多个子节点,并且B树中的每个节点都存储着多个关键字以及每个关键字所对应的数据指针。

在B树中,每个节点都有最多m个儿子和m-1个关键字,其中m被称为B树的阶。对于任意非根节点,它至少有m/2个儿子,对于根节点,它至少有2个儿子。

B树的叶子节点并不一定在同一层,因此B树的高度比平衡二叉搜索树低得多,从而可以大大减少磁盘I/O次数。

B树的操作

B树支持以下操作:

  • 搜索:查找特定的关键字,并返回指向该关键字对应数据的指针。
  • 插入:将新的关键字和数据指针插入B树中。
  • 删除:将指定的关键字和其对应的数据指针从B树中删除。

在B树中搜索、插入和删除的时间复杂度都是O(log n)级别的。

B树的应用

B树广泛用于数据库和文件系统中的索引结构设计。例如,文件系统中的文件目录和数据库中的索引都可采用B树作为底层实现。

总结

B树是一种多路平衡搜索树,可以高效地进行查找、插入和删除操作,特别适用于在大数据量下进行操作;广泛应用于数据库和文件系统的索引设计中。

代码片段

下面是用Java实现B树的代码示例:

public class BTree {
    private int order;  // B树的阶
    private Node root;  // B树的根节点

    // 定义节点类
    private class Node {
        int[] keys;  // 关键字数组
        Node[] child; // 子节点数组
        int keyNum;  // 关键字个数
        boolean isLeaf; // 是否为叶子节点

        public Node(boolean isLeaf) {
            this.keys = new int[2 * order - 1];
            this.child = new Node[2 * order];
            this.keyNum = 0;
            this.isLeaf = isLeaf;
        }
    }

    // 初始化B树
    public BTree(int order) {
        this.order = order;
        this.root = new Node(true);
    }

    // 在B树中插入关键字
    public void insert(int key) {
        Node r = root;
        if (r.keyNum == 2 * order - 1) {
            Node s = new Node(false);
            root = s;
            s.child[0] = r;
            splitChild(s, 0, r);
            insertNonFull(s, key);
        } else {
            insertNonFull(r, key);
        }
    }

    // 非满节点的插入操作
    private void insertNonFull(Node x, int key) {
        int i = x.keyNum - 1;
        if (x.isLeaf) {
            while (i >= 0 && key < x.keys[i]) {
                x.keys[i + 1] = x.keys[i];
                i--;
            }
            x.keys[i + 1] = key;
            x.keyNum++;
        } else {
            while (i >= 0 && key < x.keys[i]) {
                i--;
            }
            if (x.child[i + 1].keyNum == 2 * order - 1) {
                splitChild(x, i + 1, x.child[i + 1]);
                if (key > x.keys[i + 1]) {
                    i++;
                }
            }
            insertNonFull(x.child[i + 1], key);
        }
    }

    // 分裂满子节点
    private void splitChild(Node x, int i, Node y) {
        Node z = new Node(y.isLeaf);
        z.keyNum = order - 1;
        for (int j = 0; j < order - 1; j++) {
            z.keys[j] = y.keys[j + order];
        }
        if (!y.isLeaf) {
            for (int j = 0; j < order; j++) {
                z.child[j] = y.child[j + order];
            }
        }
        y.keyNum = order - 1;
        for (int j = x.keyNum; j >= i + 1; j--) {
            x.child[j + 1] = x.child[j];
        }
        x.child[i + 1] = z;
        for (int j = x.keyNum - 1; j >= i; j--) {
            x.keys[j + 1] = x.keys[j];
        }
        x.keys[i] = y.keys[order - 1];
        x.keyNum++;
    }
}