B 树详解及其 Java 实现

[复制链接]
发表于 2026-2-14 08:13:18 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
B 树详解及其 Java 实现

1. 弁言

B 树是一种平衡树数据结构,广泛应用于数据库和文件体系中。它是一种多路搜索树,此中每个节点可以有多个子节点和多个键。本文将具体先容 B 树的结构、性子、操纵及其 Java 实现。
2. B 树的结构与性子

2.1 B 树的界说

B 树是一种自平衡的树数据结构,具有以下性子:

  • 每个节点最多有 m 个子节点(m 为 B 树的阶)。
  • 除根节点和叶子节点外,每个节点至少有 ⌈m/2⌉ 个子节点。
  • 全部叶子节点都在同一层。
  • 每个节点包罗 n 个键(⌈m/2⌉ - 1 <= n <= m - 1)。
  • 节点的键按升序分列,节点的子节点按键值巨细分区。
2.2 B 树的应用

B 树广泛应用于数据库和文件体系中,其长处包罗:

  • 平衡性:全部叶子节点都在同一层,包管查找、插入和删除操纵的时间复杂度为 O(log n)。
  • 高效性:实用于磁盘存储,镌汰磁盘 I/O 操纵。
  • 扩展性:支持动态增删数据,得当处理惩罚大规模数据。
3. B 树的操纵

3.1 插入操纵

插入操纵包罗以下步调:

  • 查找插入位置。
  • 将键插入到相应的节点。
  • 假如节点键数高出最大值,则举行分裂操纵。
3.2 删除操纵

删除操纵包罗以下步调:

  • 查找要删除的键。
  • 从节点中删除键。
  • 假如节点键数低于最小值,则举行归并或借用操纵。
4. B 树的 Java 实现

以下是 B 树的完备 Java 实现,包罗插入和删除操纵。
4.1 B 树节点类
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. class BTreeNode<T extends Comparable<T>> {
  4.     int t;  // 最小度数
  5.     List<T> keys;  // 存储键
  6.     List<BTreeNode<T>> children;  // 存储子节点
  7.     boolean leaf;  // 是否为叶子节点
  8.     BTreeNode(int t, boolean leaf) {
  9.         this.t = t;
  10.         this.leaf = leaf;
  11.         this.keys = new ArrayList<>();
  12.         this.children = new ArrayList<>();
  13.     }
  14.     // 查找键
  15.     int findKey(T k) {
  16.         int idx = 0;
  17.         while (idx < keys.size() && keys.get(idx).compareTo(k) < 0) {
  18.             idx++;
  19.         }
  20.         return idx;
  21.     }
  22.     // 插入非满节点
  23.     void insertNonFull(T k) {
  24.         int i = keys.size() - 1;
  25.         if (leaf) {
  26.             keys.add(null);
  27.             while (i >= 0 && keys.get(i).compareTo(k) > 0) {
  28.                 keys.set(i + 1, keys.get(i));
  29.                 i--;
  30.             }
  31.             keys.set(i + 1, k);
  32.         } else {
  33.             while (i >= 0 && keys.get(i).compareTo(k) > 0) {
  34.                 i--;
  35.             }
  36.             if (children.get(i + 1).keys.size() == 2 * t - 1) {
  37.                 splitChild(i + 1, children.get(i + 1));
  38.                 if (keys.get(i + 1).compareTo(k) < 0) {
  39.                     i++;
  40.                 }
  41.             }
  42.             children.get(i + 1).insertNonFull(k);
  43.         }
  44.     }
  45.     // 分裂子节点
  46.     void splitChild(int i, BTreeNode<T> y) {
  47.         BTreeNode<T> z = new BTreeNode<>(y.t, y.leaf);
  48.         for (int j = 0; j < t - 1; j++) {
  49.             z.keys.add(y.keys.remove(t));
  50.         }
  51.         if (!y.leaf) {
  52.             for (int j = 0; j < t; j++) {
  53.                 z.children.add(y.children.remove(t));
  54.             }
  55.         }
  56.         children.add(i + 1, z);
  57.         keys.add(i, y.keys.remove(t - 1));
  58.     }
  59. }
复制代码
4.2 B 树类
  1. public class BTree<T extends Comparable<T>> {
  2.     private BTreeNode<T> root;
  3.     private int t;  // 最小度数
  4.     public BTree(int t) {
  5.         this.root = new BTreeNode<>(t, true);
  6.         this.t = t;
  7.     }
  8.     // 插入键
  9.     public void insert(T k) {
  10.         BTreeNode<T> r = root;
  11.         if (r.keys.size() == 2 * t - 1) {
  12.             BTreeNode<T> s = new BTreeNode<>(t, false);
  13.             s.children.add(r);
  14.             s.splitChild(0, r);
  15.             root = s;
  16.             s.insertNonFull(k);
  17.         } else {
  18.             r.insertNonFull(k);
  19.         }
  20.     }
  21.     // 删除键
  22.     public void delete(T k) {
  23.         if (root == null) {
  24.             return;
  25.         }
  26.         root.delete(k);
  27.         if (root.keys.isEmpty()) {
  28.             root = root.leaf ? null : root.children.get(0);
  29.         }
  30.     }
  31.     // 查找键
  32.     public boolean search(T k) {
  33.         return root == null ? false : root.search(k) != null;
  34.     }
  35. }
复制代码
4.3 B 树节点删除方法
  1. class BTreeNode<T extends Comparable<T>> {
  2.     // 其他方法省略
  3.     // 删除键
  4.     void delete(T k) {
  5.         int idx = findKey(k);
  6.         if (idx < keys.size() && keys.get(idx).compareTo(k) == 0) {
  7.             if (leaf) {
  8.                 keys.remove(idx);
  9.             } else {
  10.                 deleteFromNonLeaf(idx);
  11.             }
  12.         } else {
  13.             if (leaf) {
  14.                 return;
  15.             }
  16.             boolean flag = (idx == keys.size());
  17.             if (children.get(idx).keys.size() < t) {
  18.                 fill(idx);
  19.             }
  20.             if (flag && idx > keys.size()) {
  21.                 children.get(idx - 1).delete(k);
  22.             } else {
  23.                 children.get(idx).delete(k);
  24.             }
  25.         }
  26.     }
  27.     // 从非叶子节点删除
  28.     void deleteFromNonLeaf(int idx) {
  29.         T k = keys.get(idx);
  30.         if (children.get(idx).keys.size() >= t) {
  31.             T pred = getPred(idx);
  32.             keys.set(idx, pred);
  33.             children.get(idx).delete(pred);
  34.         } else if (children.get(idx + 1).keys.size() >= t) {
  35.             T succ = getSucc(idx);
  36.             keys.set(idx, succ);
  37.             children.get(idx + 1).delete(succ);
  38.         } else {
  39.             merge(idx);
  40.             children.get(idx).delete(k);
  41.         }
  42.     }
  43.     // 获取前驱
  44.     T getPred(int idx) {
  45.         BTreeNode<T> cur = children.get(idx);
  46.         while (!cur.leaf) {
  47.             cur = cur.children.get(cur.keys.size());
  48.         }
  49.         return cur.keys.get(cur.keys.size() - 1);
  50.     }
  51.     // 获取后继
  52.     T getSucc(int idx) {
  53.         BTreeNode<T> cur = children.get(idx + 1);
  54.         while (!cur.leaf) {
  55.             cur = cur.children.get(0);
  56.         }
  57.         return cur.keys.get(0);
  58.     }
  59.     // 填充子节点
  60.     void fill(int idx) {
  61.         if (idx != 0 && children.get(idx - 1).keys.size() >= t) {
  62.             borrowFromPrev(idx);
  63.         } else if (idx != keys.size() && children.get(idx + 1).keys.size() >= t) {
  64.             borrowFromNext(idx);
  65.         } else {
  66.             if (idx != keys.size()) {
  67.                 merge(idx);
  68.             } else {
  69.                 merge(idx - 1);
  70.             }
  71.         }
  72.     }
  73.     // 从前一个子节点借
  74.     void borrowFromPrev(int idx) {
  75.         BTreeNode<T> child = children.get(idx);
  76.         BTreeNode<T> sibling = children.get(idx - 1);
  77.         for (int i = child.keys.size() - 1; i >= 0; i--) {
  78.             child.keys.set(i + 1, child.keys.get(i));
  79.         }
  80.         if (!child.leaf) {
  81.             for (int i = child.children.size() - 1; i >= 0; i--) {
  82.                 child.children.set(i + 1, child.children.get(i));
  83.             }
  84.         }
  85.         child.keys.set(0, keys.get(idx - 1));
  86.         if (!child.leaf) {
  87.             child.children.set(0, sibling.children.remove(sibling.children.size() - 1));
  88.         }
  89.         keys.set(idx - 1, sibling.keys.remove(sibling.keys.size() - 1));
  90.     }
  91.     // 从下一个子节点借
  92.     void borrowFromNext(int idx) {
  93.         BTreeNode<T> child = children.get(idx);
  94.         BTreeNode<T> sibling = children.get(idx +
  95. 1);
  96.         child.keys.add(keys.get(idx));
  97.         if (!child.leaf) {
  98.             child.children.add(sibling.children.remove(0));
  99.         }
  100.         keys.set(idx, sibling.keys.remove(0));
  101.     }
  102.     // 合并子节点
  103.     void merge(int idx) {
  104.         BTreeNode<T> child = children.get(idx);
  105.         BTreeNode<T> sibling = children.get(idx + 1);
  106.         child.keys.add(keys.remove(idx));
  107.         for (int i = 0; i < sibling.keys.size(); i++) {
  108.             child.keys.add(sibling.keys.get(i));
  109.         }
  110.         if (!child.leaf) {
  111.             for (int i = 0; i < sibling.children.size(); i++) {
  112.                 child.children.add(sibling.children.get(i));
  113.             }
  114.         }
  115.         children.remove(sibling);
  116.     }
  117.     // 查找键
  118.     BTreeNode<T> search(T k) {
  119.         int idx = findKey(k);
  120.         if (idx < keys.size() && keys.get(idx).compareTo(k) == 0) {
  121.             return this;
  122.         }
  123.         if (leaf) {
  124.             return null;
  125.         }
  126.         return children.get(idx).search(k);
  127.     }
  128. }
复制代码
5. 示例测试
  1. public class Main {
  2.     public static void main(String[] args) {
  3.         BTree<Integer> bTree = new BTree<>(3);
  4.         bTree.insert(10);
  5.         bTree.insert(20);
  6.         bTree.insert(5);
  7.         bTree.insert(6);
  8.         bTree.insert(12);
  9.         bTree.insert(30);
  10.         bTree.insert(7);
  11.         bTree.insert(17);
  12.         System.out.println("B树创建成功。");
  13.         if (bTree.search(6)) {
  14.             System.out.println("找到键 6");
  15.         } else {
  16.             System.out.println("未找到键 6");
  17.         }
  18.         bTree.delete(6);
  19.         if (bTree.search(6)) {
  20.             System.out.println("找到键 6");
  21.         } else {
  22.             System.out.println("未找到键 6");
  23.         }
  24.     }
  25. }
复制代码
6. 运行结果

运行上述代码将演示 B 树的插入和删除操纵。B 树将按次序插入键,然后删除键 6 并举行查找验证。
7. 总结

本文具体先容了 B 树的数据结构及其在 Java 中的实现,包罗插入、删除和查找操纵。通过明白和实践这些内容,可以资助你更好地把握 B 树的实现和应用。盼望本文对你有所资助,如有任何疑问或发起,接待留言讨论。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表