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.准备工作

//节点类
class BTreeNode {// B树的阶数int t;List<Integer> keys;//关键字List<BTreeNode> childNodes;//孩子boolean leaf;//判断节点是否是叶子结点public BTreeNode(int t, boolean leaf) {this.t = t;this.leaf = leaf;this.keys = new ArrayList<>();this.childNodes = new ArrayList<>();}
}

2.升序遍历树

 public void traverse() {int i;for (i = 0; i < keys.size(); i++) {if (!leaf) {//去索引为i的孩子里面继续找childNodes.get(i).traverse();}System.out.print(keys.get(i) + " ");}//最后还剩一个关键字的孩子节点if (!leaf) {childNodes.get(i).traverse();}}

3.查找值所在的位置

 public int search(int key) {int i = 0;//先找到比值小和等的节点 然后小的递归找孩子while (i < keys.size() && key > keys.get(i)) {i++;}//等的if (i < keys.size() && key == keys.get(i)) {return i;} else if (leaf) {//都到叶子了还没找到就无了return -1;} else {//递归继续去他的子节点找  小的return childNodes.get(i).search(key);}}

4.添加

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

5.分裂

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

6.遍历查询

class BTree {BTreeNode root;//根节点int t;//树中的最小度数//指定默认树的度数是2public BTree() {this(2);}public BTree(int t) {this.root = null;this.t = t;}//遍历树public void traverse() {//树不为空就可以遍历if (root != null) {root.traverse();}}//查找节点的位置public int search(int key) {if (root != null) {return root.search(key);}return -1;}//插入节点public void insert(int key) {if (root == null) {root = new BTreeNode(t, true);root.keys.add(0, key);} else {if (root.keys.size() == (2 * t) - 1) {BTreeNode s = new BTreeNode(t, false);s.childNodes.add(0, root);s.splitChild(0, root);int i = 0;if (s.keys.get(0) < key) {i++;}s.childNodes.get(i).insertNonFull(key);root = s;} else {root.insertNonFull(key);}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/107183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

260. 只出现一次的数字 III

给你一个整数数组 nums&#xff0c;其中恰好有两个元素只出现一次&#xff0c;其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。 你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。 示例 1&#xff1a; 输入&…

计算机基础知识32

Socket抽象层(socket编程) # Socket是在应用层和传输层之间的一个抽象层&#xff0c;它把TCP/IP层复杂的操作抽象为几个简单 的接口供应用层调用已实现进程在网络中通信 socket () 对象 bind () 函数来绑定 listen () 监听&#xff0c;等别人电话 accept&#xff08;&#…

canal rocketmq

上篇文章canal 消费进度说到直接使用ClusterCanalConnector并发消费是有问题的&#xff0c;可以先用单点将canal事件发送到mq中&#xff0c;再由mq并发处理&#xff0c;另外mq还可以做到削峰的作用&#xff0c;让canal数据不至于阻塞。 使用队列&#xff0c;可以自己起一个单实…

AI电销机器人好不好用关键是什么?

影响AI电销机器人是否好用的两个因素分别是&#xff0c;识别系统以及线路。 有很多电销企业都想找一个好用的AI电销机器人&#xff0c;可是什么样的机器人才是好用的机器人呢?有哪些因素会影响AI电销机器人好不好用呢? 添加图片注释&#xff0c;不超过 140 字&#xff08;可选…

groupnorm_backward反向公式推导

前向 均值 μ n g ∑ i 1 M ( X i ) M (1) {\large \mathit{\color{Blue} \mu_{ng} \frac{\sum_{i1}^M(X^{i})}{M}} } \tag{1} μng​M∑i1M​(Xi)​(1) 方差 σ n g 2 ∑ i 1 M ( X i − μ n g ) M (2) {\large \mathit{\color{Blue} \sigma_{ng}^2 \frac{\sum_{i …

在 Linux 上保护 SSH 服务器连接的 8 种方法

SSH 是一种广泛使用的协议&#xff0c;用于安全地访问 Linux 服务器。大多数用户使用默认设置的 SSH 连接来连接到远程服务器。但是&#xff0c;不安全的默认配置也会带来各种安全风险。 具有开放 SSH 访问权限的服务器的 root 帐户可能存在风险。尤其是如果使用的是公共 IP 地…

qt中json类

目录 QJsonValue QJsonObject QJsonArray QJsonDocument 案例&#xff1a; Qt 5.0开始提供了对Json的支持&#xff0c;我们可以直接使用Qt提供的Json类进行数据的组织和解析&#xff0c;下面介绍4个常用的类。 QJsonValue 该类封装了JSON支持的数据类型。 布尔类型&#xf…

【Power BI】Power BI 入门指南:版本、下载和报表创建的步骤

文章目录 一、前言二、了解 Power BI 版本三、下载 Power BI Desktop四、如何开始使用 Power BI Desktop五、在 Power BI Desktop 中创建报表六、文末总结 一、前言 Power BI 是微软于 2013 年推出的产品&#xff0c;为一款商业智能与数据可视化工具。它通过引人注目的视觉效果…

[Linux 基础] Linux编辑器Vim,你值得拥有

文章目录 1、Linux 软件包管理器 yum1.1 什么是软件包1.2 如何安装软件1.3 如何卸载软件 2、vim的使用2.1 vim的安装和配置2.2 vim的基本概念2.3 vim的基本操作 3、vim正常模式命令集4、vim注释与去注释5、Liunx编辑器-gcc/g使用5.1 如何使用gcc编译c程序5.2 gcc的翻译过程5.2.…

Python-pyecharts和pandas库

目录 pyecharts库 pandas库 示例1 示例2 pyecharts库 pyecharts是一个基于Python的交互式数据可视化库&#xff0c;旨在帮助用户轻松地创建各种类型的图表和可视化效果。该库是在Echarts开源项目的基础上开发的&#xff0c;Echarts是一款由百度开发的优秀的数据可视化工具。…

为什么机器学习中需要假设检验

最近由于研究需要&#xff0c;需要在机器学习项目的结果中加入假设检验的内容&#xff0c;但是机器学习中的假设检验和数理统计中的假设检验不同&#xff0c;是数理统计中假设检验的延申。但是&#xff0c;本来假设检验就是数理统计中的比较绕的一部分&#xff0c;比较难懂&…

泛在电力物联网的关键技术与未来发展策略-安科瑞黄安南

摘要: 文章分析了泛在电力物联网的内涵及其主要特征&#xff0c;针对泛在电力物联网的建设目标、基本构架以及关键技术与未来发展策略进行综合探讨&#xff0c;期待得到专业人士的指点。 关键词: 泛在电力物联网&#xff0c; 网络规划&#xff0c; 网络发展 随着能源革命的不…

MAC版idea如何安装maven?

什么是maven项目 Maven 是 Apache 组织下的一个跨平台的项目管理工具,它主要用来帮助实现项目的构建、测试、打包和部署。它的跨平台性保证了在不同的操作系统上可以使用相同的命令来完成相应的任务。 为什么选择Maven项目,而非普通的Java项目。普通的Java项目如果依赖其他…

kafka消费者程序日志报错Offset commit failed问题研究

生产环境偶尔会遇到kafka消费者程序日志报错的问题 截取主要日志如下&#xff1a; 2023-10-02 19:35:28.554 {trace: d7f97f70dd693e3d} ERROR[Thread-49:137] ConsumerCoordinator$OffsetCommitResponseHandler.handle(812) - [Consumer clientIdconsumer-1, groupIdcid_yin…

计算机网络基础(三):IPv4编址方式、子网划分、IPv4通信的建立与验证及ICMP协议

**IPv4地址是一个32位长的二进制数。**而这个32位二进制数又通常会表示为4个用点隔开的十进制数。那么&#xff0c;这个32位二进制数要如何通过4个十进制数表示出来呢&#xff1f; 我们在配置IPv4地址时&#xff0c;同时配置的“掩码”又有何用途&#xff1f; 1.IPv4编址方式…

第 367 场 LeetCode 周赛题解

A 找出满足差值条件的下标 I 模拟 class Solution { public:vector<int> findIndices(vector<int> &nums, int indexDifference, int valueDifference) {int n nums.size();for (int i 0; i < n; i)for (int j 0; j < i; j)if (i - j > indexDiffe…

软件测试的调用接口怎么调用,逻辑是什么?

一、什么是接口测试&#xff1f; 接口测试是测试系统组件之间接口的测试。接口主要用于检测外部系统和内部子系统之间的交互点。测试的重点是检查数据交换、传输、控制和管理过程&#xff0c;以及系统之间的相互逻辑依赖。 二、为什么要做接口测试&#xff1f; 在淘宝系统的历…

Go编程:使用 Colly 库下载Reddit网站的图像

概述 Reddit是一个社交新闻网站&#xff0c;用户可以发布各种主题的内容&#xff0c;包括图片。本文将介绍如何使用Go语言和Colly库编写一个简单的爬虫程序&#xff0c;从Reddit网站上下载指定主题的图片&#xff0c;并保存到本地文件夹中。为了避免被目标网站反爬&#xff0c…

C++入门篇(3)---引用

1.引用 你有没有被人起过外号?比如身边的朋友,喊他的时候不会叫他的全名,像我很好的朋友,我一般都喜欢叫他"阿威",而不会去称呼全名.我叫他"阿威",他还是他没有什么问题. 这里新登场的引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&am…

多线程使用处理数据库导致锁表解决办法

问题描述&#xff1a; 当使用ON DUPLICATE KEY UPDATE的sql来访问时&#xff0c; 可能会出现多个线程同时写入一个已有的数据里。 解决办法&#xff1a; 使用 REPLACE INTO 原因&#xff1a; 保持更好的并发性&#xff1a;REPLACE INTO 在插入记录时会先删除原有记录&#xf…