• Java实现B树


    1.介绍

    B树是一种自平衡的搜索树数据结构,常用于数据库和文件系统中的索引结构。它具有以下好处和功能:

    1. 高效的查找操作:B树的特点是每个节点可以存储多个关键字,并且保持有序。通过在节点上进行二分查找,可以快速定位目标关键字的位置,从而实现高效的查找操作。

    2. 平衡性:B树通过自平衡的方式维护树的平衡性,即保证树的每个叶子节点到根节点的路径长度相等。这种平衡性能够确保各种操作的时间复杂度保持在较低水平,例如插入、删除和查找等操作都可以在对数时间内完成。

    3. 适应大型数据集:B树适用于存储大型数据集,并且可以处理非常大的索引。其节点可以存储多个关键字,因此在相同层数的情况下,B树可以存储更多的数据。

    4. 支持范围查询:由于B树的节点有序,因此可以很方便地进行范围查询。通过定位范围的起始和结束关键字所在的节点,可以快速地获取指定范围内的数据。

    5. 高效的插入和删除操作:B树通过平衡性的维护,使得插入和删除操作具有较低的时间复杂度。它可以通过调整节点的结构,避免过深或过浅的树结构,从而保持树的平衡。

    总的来说,B树是一种高效的数据结构,能够应对大规模数据集的索引需求,并提供快速的查找、插入和删除操作。它在数据库和文件系统中广泛应用,为数据的组织和访问提供了便利。

    2.代码分析

    1.分裂

    当键的数量超过 2t - 1的时候就会进行分裂操作,规则就是中间的向上分裂,大的交给一个新的节点,小的交给自己

    如果不是叶子节点就需要把后半部分子节点给新的节点,

    2.添加

    1. 首先,根据给定的关键字,从根节点开始向下搜索,找到合适的叶子节点。

    2. 在叶子节点中插入新的关键字。如果叶子节点未满,直接插入;否则,执行步骤3。

    3. 当叶子节点已满时,需要进行分裂操作。将当前节点一分为二,得到两个新的叶子节点,并选择一个关键字提升到父节点中。

    4. 如果父节点也已满,则重复步骤3,层层递归地向上分裂,直到找到一个非满节点或达到树的顶部。

    5. 完成插入操作后,需要更新祖先节点的关键字信息。如果某个节点发生了分裂,它提升的关键字需要插入到其父节点中,并根据大小顺序进行调整。

    通过以上步骤,B树的插入操作可以保持树的平衡性。在插入过程中,B树会根据节点的容量进行自动调整,使得树的高度保持相对较低,从而确保各种操作的效率。

    需要注意的是,在插入操作中可能会出现关键字重复的情况。对于B树来说,可以允许存在相同的关键字,而在查找操作时,会按照节点中关键字的大小顺序进行搜索。因此,在插入过程中需要根据具体需求来处理关键字重复的情况。

    3.查找

    1. 从根节点开始,比较要查找的关键字与当前节点中的关键字。

    2. 如果找到了匹配的关键字,则表示查找成功,结束操作。

    3. 如果要查找的关键字小于当前节点的最小关键字,则进入当前节点的左子树进行继续查找。

    4. 如果要查找的关键字大于当前节点的最大关键字,则进入当前节点的右子树进行继续查找。

    5. 重复步骤 3 和 4,直到找到匹配的关键字或者到达叶子节点。

    6. 如果到达叶子节点仍然没有找到匹配的关键字,则表示查找失败,结束操作。

    在B树的查找过程中,关键字的比较会指导搜索方向,通过不断地按照关键字的大小顺序向下搜索,可以快速地找到目标关键字或者判断其不存在。

    需要注意的是,B树中允许存在相同的关键字,因此在查找操作中,如果存在多个相同的关键字,可以根据具体需求选择返回其中一个或全部。此外,B树的查找操作具有较好的平均时间复杂度,可以在较短的时间内完成查询。

    3.代码实现

    1.准备工作

    1. //节点类
    2. class BTreeNode {
    3. // B树的阶数
    4. int t;
    5. List keys;//关键字
    6. List childNodes;//孩子
    7. boolean leaf;//判断节点是否是叶子结点
    8. public BTreeNode(int t, boolean leaf) {
    9. this.t = t;
    10. this.leaf = leaf;
    11. this.keys = new ArrayList<>();
    12. this.childNodes = new ArrayList<>();
    13. }
    14. }

    2.升序遍历树

    1. public void traverse() {
    2. int i;
    3. for (i = 0; i < keys.size(); i++) {
    4. if (!leaf) {
    5. //去索引为i的孩子里面继续找
    6. childNodes.get(i).traverse();
    7. }
    8. System.out.print(keys.get(i) + " ");
    9. }
    10. //最后还剩一个关键字的孩子节点
    11. if (!leaf) {
    12. childNodes.get(i).traverse();
    13. }
    14. }

    3.查找值所在的位置

    1. public int search(int key) {
    2. int i = 0;
    3. //先找到比值小和等的节点 然后小的递归找孩子
    4. while (i < keys.size() && key > keys.get(i)) {
    5. i++;
    6. }
    7. //等的
    8. if (i < keys.size() && key == keys.get(i)) {
    9. return i;
    10. } else if (leaf) {//都到叶子了还没找到就无了
    11. return -1;
    12. } else {
    13. //递归继续去他的子节点找 小的
    14. return childNodes.get(i).search(key);
    15. }
    16. }

    4.添加

    1. public void insertNonFull(int key) {//处理节点未满的情况
    2. int i = keys.size() - 1;
    3. if (leaf) {//叶节点
    4. while (i >= 0 && key < keys.get(i)) {//从后往前 找出比你小的那个i
    5. i--;
    6. }
    7. keys.add(i + 1, key);//因为第i个位置是比你小的,所以你要插入后面一个
    8. } else {//非叶节点
    9. while (i >= 0 && key < keys.get(i)) {//找到要插入子节点的位置
    10. i--;
    11. }
    12. //判断子节点是否需要分裂操作
    13. if (childNodes.get(i + 1).keys.size() == (2 * t) - 1) {
    14. splitChild(i + 1, childNodes.get(i + 1));
    15. if (key > keys.get(i + 1)) {
    16. i++;
    17. }
    18. }
    19. //分裂完毕 或者 不需要分裂 递归插入
    20. childNodes.get(i + 1).insertNonFull(key);
    21. }
    22. }

    5.分裂

    1. public void splitChild(int i, BTreeNode y) {//处理节点满的情况进行分裂操作
    2. BTreeNode z = new BTreeNode(y.t, y.leaf);
    3. keys.add(i, y.keys.get(t - 1));//中间的上移
    4. childNodes.add(i + 1, z);//创建新的孩子
    5. for (int j = 0; j < t - 1; j++) {//后面的移动到新的里面
    6. z.keys.add(j, y.keys.get(j + t));
    7. }
    8. if (!y.leaf) {//后半部分子节点移动到新的节点
    9. for (int j = 0; j < t; j++) {
    10. z.childNodes.add(j, y.childNodes.get(j + t));
    11. }
    12. }
    13. //主要总用时为了情况没有用的部分
    14. //获取被拆分节点后半部分的关键字和子节点部分。
    15. y.keys.subList(t - 1, y.keys.size()).clear();
    16. //方法用于删除列表中的元素(获取完删除)
    17. y.childNodes.subList(t, y.childNodes.size()).clear();
    18. }
    19. }

    6.遍历查询

    1. class BTree {
    2. BTreeNode root;//根节点
    3. int t;//树中的最小度数
    4. //指定默认树的度数是2
    5. public BTree() {
    6. this(2);
    7. }
    8. public BTree(int t) {
    9. this.root = null;
    10. this.t = t;
    11. }
    12. //遍历树
    13. public void traverse() {
    14. //树不为空就可以遍历
    15. if (root != null) {
    16. root.traverse();
    17. }
    18. }
    19. //查找节点的位置
    20. public int search(int key) {
    21. if (root != null) {
    22. return root.search(key);
    23. }
    24. return -1;
    25. }
    26. //插入节点
    27. public void insert(int key) {
    28. if (root == null) {
    29. root = new BTreeNode(t, true);
    30. root.keys.add(0, key);
    31. } else {
    32. if (root.keys.size() == (2 * t) - 1) {
    33. BTreeNode s = new BTreeNode(t, false);
    34. s.childNodes.add(0, root);
    35. s.splitChild(0, root);
    36. int i = 0;
    37. if (s.keys.get(0) < key) {
    38. i++;
    39. }
    40. s.childNodes.get(i).insertNonFull(key);
    41. root = s;
    42. } else {
    43. root.insertNonFull(key);
    44. }
    45. }
    46. }
    47. }

  • 相关阅读:
    软件杯 深度学习 opencv python 实现中国交通标志识别_1
    07 【nodejs内置模块(下)】
    被杭州某抖音代运营公司坑了
    1--Linux:环境安装与Linux常识
    想要精通算法和SQL的成长之路 - 二叉树的判断问题(子树判断 | 对称性 | 一致性判断)
    华为数通方向HCIP-DataCom H12-821题库(单选题:281-300)
    深入理解JVM虚拟机第十八篇:JVM种局部变量表结构的认识
    html文件中引入.ts文件并运行
    Git纯操作版 项目添加和提交、SSH keys添加、远程仓库控制、冲突解决、IDEA连接使用
    选择最适合你的图像分类模型
  • 原文地址:https://blog.csdn.net/m0_74749208/article/details/133775949