B树的简单实现

ops/2024/11/22 9:16:18/
template<class K, size_t M>
struct BTreeNode
{K _keys[M]; // 用于存储关键字的数组,最多容纳 M 个关键字(超额一个,为分裂提供空间)。BTreeNode<K, M>* _subs[M + 1]; // 存储子节点的指针数组,最多 M+1 个子节点。BTreeNode<K, M>* _parent; // 指向父节点的指针。size_t _n; // 当前节点中实际存储的关键字数量。// 构造函数,初始化节点的各个属性。BTreeNode(){for (size_t i = 0; i < M; i++){_keys[i] = K(); // 初始化关键字数组为默认值。_subs[i] = nullptr; // 初始化子节点指针为空。}_subs[M] = nullptr; // 多余的子节点指针初始化为空。_parent = nullptr; // 父节点初始化为空。_n = 0; // 初始关键字数量为 0。}
};
  • 作用:定义 B 树节点的结构,包括关键字数组、子节点指针、父节点指针和当前节点的关键字数量。
  • 意义
    • 为 B 树的基本操作(插入、删除、查找等)提供节点存储结构。
    • 允许节点存储最多 M 个关键字和 M+1 个子节点。

template<class K, size_t M>
class BTree
{typedef BTreeNode<K, M> Node; // 定义一个别名,便于后续引用节点类型。public:pair<Node*, int> Find(const K& key)
{Node* cur = _root; // 从根节点开始查找。Node* parent = nullptr; // 记录当前节点的父节点。while (cur){size_t i = 0;// 在当前节点中逐一比较关键字while (i < cur->_n){if (key < cur->_keys[i]) // 如果目标关键字小于当前关键字,停止查找。{break;}else if (key > cur->_keys[i]) // 如果目标关键字大于当前关键字,继续查找。{i++;}else // 找到目标关键字,返回节点和索引。{return make_pair(cur, i);}}parent = cur; // 更新父节点为当前节点。cur = cur->_subs[i]; // 进入对应的子节点。}return make_pair(parent, -1); // 未找到,返回最近的父节点及无效索引。
}void InsertKey(Node* node, const K& key, Node* child)
{int end = node->_n - 1; // 从节点的最后一个关键字开始比较。while (end >= 0){if (key < node->_keys[end]) // 如果新关键字小于当前关键字,向右移动当前关键字和其右子树。{node->_keys[end + 1] = node->_keys[end];node->_subs[end + 2] = node->_subs[end + 1];end--;}else // 如果新关键字大于等于当前关键字,停止移动。{break;}}node->_keys[end + 1] = key; // 插入新关键字。node->_subs[end + 2] = child; // 插入对应的子节点。if (child){child->_parent = node; // 更新子节点的父节点指针。}node->_n++; // 更新节点的关键字数量。
}bool Insert(const K& key)
{if (_root == nullptr) // 如果树为空,创建根节点并插入关键字。{_root = new Node;_root->_keys[0] = key;_root->_n++;return true;}// key已经存在,不允许插入pair<Node*, int> ret = Find(key);if (ret.second >= 0){return false;}K newKey = key; // 保存当前要插入的关键字。Node* child = nullptr; // 保存分裂后产生的新节点。Node* parent = ret.first; // 从查找到的父节点开始插入。while (1){InsertKey(parent, newKey, child); // 插入关键字到节点。if (parent->_n < M) // 如果节点未满,插入完成。{return true;}else // 如果节点满了,进行分裂。{size_t mid = M / 2; // 找到中间关键字的位置。Node* brother = new Node; // 创建一个新节点作为兄弟节点。size_t j = 0;size_t i = mid + 1;for (; i <= M - 1; i++) // 将中间关键字右边的部分移动到兄弟节点。{brother->_keys[j] = parent->_keys[i];brother->_subs[j] = parent->_subs[i];if (parent->_subs[i]){parent->_subs[i]->_parent = brother;}j++;}brother->_subs[j] = parent->_subs[i]; // 拷贝最后一个右子树。if (parent->_subs[i]){parent->_subs[i]->_parent = brother;}brother->_n = j; // 更新兄弟节点的关键字数量。parent->_n -= (brother->_n + 1); // 更新父节点的关键字数量。K midkey = parent->_keys[mid]; // 提取中间关键字。parent->_keys[mid] = K(); // 清空中间关键字。if (parent->_parent == nullptr) // 如果分裂的是根节点,创建新根节点。{_root = new Node;_root->_keys[0] = midkey;_root->_subs[0] = parent;_root->_subs[1] = brother;_root->_n = 1;parent->_parent = _root;brother->_parent = _root;break;}else // 如果分裂的不是根节点,继续向上插入。{newKey = midkey;child = brother;parent = parent->_parent;}}}return true;
}void _Inorder(Node* root)
{if (root == nullptr){return;}size_t i = 0;for (i = 0; i < root->_n; i++) // 遍历当前节点的关键字和子树。{_Inorder(root->_subs[i]); // 递归遍历左子树。cout << root->_keys[i] << " "; // 打印当前关键字。}_Inorder(root->_subs[i]); // 遍历最后一个右子树。
}

 

void TestBtree()
{int a[] = {53, 139, 75, 49, 145, 36, 101}; // 要插入的关键字数组。BTree<int, 3> t; // 创建阶数为 3 的 B 树。for (auto e : a){t.Insert(e); // 插入每个关键字。}t.Inorder(); // 打印中序遍历结果。
}


http://www.ppmy.cn/ops/135744.html

相关文章

Vue 3 + Vite:构建闪电般快速的开发环境

引言 在现代前端开发中&#xff0c;开发效率和构建性能至关重要。Vue 3 配合 Vite 构建工具为开发者带来了前所未有的开发体验。本文将详细介绍如何使用这个强大的组合来提升开发效率。 Vite 的优势 1. 极速的冷启动 基于 ES modules 的开发服务器按需编译&#xff0c;不需…

不需要双手离开键盘 vscode

目标是“不需要双手离开键盘”&#xff01; ctrl shift O 打开函数导航窗格 ctrl enter 行中换行 alt ↑/↓上下移行 shift alt ↑/↓上下复制 ctrl ←/→ 按代码块移动 ctrl delete / backspace按代码块删除 ctrl l 选择单行 shift delete 删除整行 ctrl C/V 复制/…

k8s1.30.0高可用集群部署

负载均衡 nginx负载均衡 两台nginx负载均衡 vim /etc/nginx/nginx.conf stream {upstream kube-apiserver {server 192.168.0.11:6443 max_fails3 fail_timeout30s;#server 192.168.0.12:6443 max_fails3 fail_timeout30s;#server 192.168.0.13:6443 max_fails3…

鸿蒙 ArkTS 中文本居中对齐的坑:为何设置宽度至关重要?

引言&#xff1a; 在开发过程中&#xff0c;我们经常会遇到布局问题&#xff0c;尤其是文本的对齐问题。在使用 鸿蒙 ArkTS 进行开发时&#xff0c;我遇到了一个看似简单却容易被忽视的问题&#xff1a;文本居中对齐。问题的根源在于&#xff0c;当使用 Text 组件进行文本居中…

Python自动化测试实践中pytest用到的功能dependency和parametrize

Python自动化测试中pytest用到的功能 1、pytest之@pytest.mark.dependency装饰器设置测试用例之间的依赖关系 1.1说明: 1、这是一个pytest第三方插件,主要解决用例之间的依赖关系。如果依赖的上下文测试用例失败后续的用例会被标识为跳过执行,相当于执行了 pytest.mark.s…

【http】http协议状态码

目录 1. 说明2. 信息性状态码3. 成功状态码4. 重定向状态码5. 客户端错误状态码6. 服务器错误状态码 1. 说明 1.HTTP协议状态码是指在HTTP通信过程中&#xff0c;服务器向客户端返回的三位数值的数字代码&#xff0c;用于表示服务器对请求的处理结果和状态。2.这些状态码由三个…

Unet++改进38:添加GLSA(2024最新改进方法)具有聚合和表示全局和局部空间特征的能力,这有利于分别定位大目标和小目标

本文内容:添加GLSA注意力机制 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 基于变压器的模型已经被广泛证明是成功的计算机视觉任务,通过建模远程依赖关系和捕获全局表示。然而,它们往往被大模式的特征所主导,导致局部细节(例如边界和小物体)的丢失…

【定长滑动窗口】【刷题笔记】

标题&#xff1a;《2841. 几乎唯一子数组的最大和问题解析》 在本文中&#xff0c;我们将深入探讨力扣上的 2841. 几乎唯一子数组的最大和这一问题&#xff0c;并详细解析两种不同的解答思路。 一、题目描述 给定一个整数数组 nums 和两个正整数 m 和 k。要求返回 nums 中长…