当前位置: 首页 > news >正文

学习一下B树和B+树

学习一下B树和B+树

前言

​ 抱歉这里鸽了5天,笔者最近忙于秋招找工作,连一些项目都被暂时的搁置了。这里笔者再干一个需要手搓B+树的题目中遇到了,虽然知道这个题大致需要使用B+树解决问题,但是发现自己好像对B/B+树实际上不够熟悉,这里笔者整理一下笔记放到下面,供各位参考和批评。

可以在哪里看到他们呢?

​ 在数据库和文件系统中,B树(Balanced Tree)和B+树是核心的数据结构。它们通过多路平衡搜索,提供高效的查找、插入和范围查询能力。换而言之,在比较注重关系类型的查询的时候,我们很容易联想到使用B/B+树来进行关系的构建。

​ 以文件系统为例子,我们可以非常自然的想到,我们的目录节点是一个非叶子节点(我指代的是下面还有孩子节点,对于二叉树,这个个数非常固定的就是2,这个无可厚非),下面存储若干的子节点(也不一定是叶子节点),所以我们的节点立马也就变成了这样的结构:

    struct Node {bool isLeaf;std::vector<T> keys;	// T是一个给定的类型 std::vector<Node*> children;Node* next;Node(bool leaf) : isLeaf(leaf), next(nullptr) {}};

​ 因此,在一个存在层次(使用目录的)的文件系统中,我们实际上就是查找由Node构成的B(+)树的结构。

[charliechen@Charliechen CChatRoom]$ tree .
.
├── client
│   ├── client_loader.cpp
│   └── CMakeLists.txt
├── CMakeLists.txt
├── library
│   ├── CMakeLists.txt
│   ├── simple_logger
│   │   ├── simple_logger.cpp
│   │   └── simple_logger.h
│   └── sockets_operation
│       ├── passive_client_socket.hpp
│       ├── socket_error.hpp
│       ├── sockets_common.hpp
│       ├── sockets_driver_impl.h
│       ├── sockets_driver_impl_linux.cpp
│       ├── sockets_driver_impl_linux.h
│       ├── sockets_operation.cpp
│       └── sockets_operation.h
├── server
│   └── CMakeLists.txt
└── test├── CMakeLists.txt├── test_client.cpp└── test_sockets.cpp

​ B树(B+树)这样的数据结构。下面我们来看看概念。

B树(Balanced Tree)

B树是一种多路平衡搜索树,用于在磁盘或内存中高效存储大量数据。它保证树的高度为对数级别,因此查找、插入、删除操作的时间复杂度均为 O(log⁡n)O(\log n)O(logn)

​ 我们要求,一个B树的特点必须是:

  1. 多路节点:一个节点可以有多个子节点,而不仅限于二叉。
  2. 关键字有序:节点内关键字按升序排列。
  3. 所有叶子节点在同一层:保证平衡。
  4. 节点关键字和子树数约束
    • 阶数 M 的 B 树,每个节点关键字数在 [⌈M/2⌉−1,M−1][⌈M/2⌉-1, M-1][⌈M/21,M1]这样的约束是为了保证
    • 子树数在 [⌈M/2⌉,M][⌈M/2⌉, M][⌈M/2,M]
  5. 查找过程
    • 在节点关键字中查找目标值或确定进入哪颗子树。
    • 递归查找,直到叶子节点或找到目标。
几个经典的操作
  • 查找:类似二分查找,沿着多路节点向下查找。
  • 插入
    • 找到合适叶子节点。
    • 插入关键字。
    • 节点满时分裂,可能递归向上分裂。
  • 删除
    • 删除关键字。
    • 节点关键字数不足时,向兄弟节点借或合并。

B+树

特点

​ B+树实际上就是B树的一点改进,由于非叶子节点不存储信息,直接查叶子节点就好了。

  1. 非叶子节点只存索引:不存储具体数据,节省空间。
  2. 叶子节点存储所有数据:并按照关键字顺序形成链表。
  3. 查找路径固定:所有查找操作最终都在叶子节点完成。
  4. 范围查询高效:叶子链表支持顺序扫描,方便扫描范围数据。
  5. 多路平衡:和B树类似,保持高度平衡。
特性B树B+树
数据存储位置非叶子节点 + 叶子节点仅叶子节点
非叶子节点存索引和数据仅存索引
叶子节点无链表叶子链表支持顺序遍历
查找路径命中可提前结束必须到叶子节点
范围查询中序遍历叶子链表顺序扫描
磁盘IO查找路径短内部节点更小,扇出大,总体IO少
应用场景小型索引数据库索引、文件系统

​ 一个潜在的模板代码

#include <iostream>
#include <vector>
#include <algorithm>template <typename T, int M = 4>
class BPlusTree {struct Node {bool isLeaf;std::vector<T> keys;std::vector<Node*> children;Node* next;Node(bool leaf) : isLeaf(leaf), next(nullptr) {}};Node* root;std::pair<T, Node*> split(Node* node) {int mid = node->keys.size() / 2;Node* right = new Node(node->isLeaf);right->keys.assign(node->keys.begin() + mid, node->keys.end());node->keys.resize(mid);if (!node->isLeaf) {right->children.assign(node->children.begin() + mid + 1, node->children.end());node->children.resize(mid + 1);}if (node->isLeaf) {right->next = node->next;node->next = right;}return { right->keys[0], right };}std::pair<T, Node*> insert(Node* node, const T& key) {if (node->isLeaf) {auto it = std::upper_bound(node->keys.begin(), node->keys.end(), key);node->keys.insert(it, key);} else {int i = 0;while (i < node->keys.size() && key >= node->keys[i]) i++;auto ret = insert(node->children[i], key);if (ret.second) {node->keys.insert(node->keys.begin() + i, ret.first);node->children.insert(node->children.begin() + i + 1, ret.second);}}if (node->keys.size() >= M) return split(node);return { T(), nullptr };}public:BPlusTree() { root = new Node(true); }void insert(const T& key) {auto ret = insert(root, key);if (ret.second) {Node* newRoot = new Node(false);newRoot->keys.push_back(ret.first);newRoot->children.push_back(root);newRoot->children.push_back(ret.second);root = newRoot;}}bool search(const T& key) {Node* cur = root;while (!cur->isLeaf) {int i = 0;while (i < cur->keys.size() && key >= cur->keys[i]) i++;cur = cur->children[i];}return std::find(cur->keys.begin(), cur->keys.end(), key) != cur->keys.end();}void printAll() {Node* cur = root;while (!cur->isLeaf) cur = cur->children[0];while (cur) {for (auto k : cur->keys) std::cout << k << " ";cur = cur->next;}std::cout << std::endl;}
};int main() {BPlusTree<int,4> tree;for(int x: {10,20,5,15,25,30,1}) tree.insert(x);std::cout << "查找15: " << tree.search(15) << std::endl;std::cout << "查找7: " << tree.search(7) << std::endl;std::cout << "顺序遍历: ";tree.printAll();
}
http://www.dtcms.com/a/335717.html

相关文章:

  • map和join的用法
  • K8S集群环境搭建
  • [激光原理与应用-291]:理论 - 波动光学 - 相关光与不相干光:光的干涉不是随随便便就能产生的,需要满足严格的条件方能产生光的干涉(条纹)
  • 【科研绘图系列】R语言绘制探究浮游植物成熟阶段的光合作用与溶解性有机碳
  • OpenCV 图像处理核心技术:边界填充、算术运算与滤波处理实战
  • 在 Element UI 的 el-table 中实现某行标红并显示删除线
  • Leaflet赋能:WebGIS视角下的省域区县天气可视化实战攻略
  • Python训练营打卡Day35-复习日
  • 数据赋能(396)——大数据——抽象原则
  • 奈飞工厂无广告纯净版官方下载,最新官网入口
  • 常用的SQL语句
  • 使用vscode的task.json来自动执行make命令,而不直接使用终端
  • java八股文-(spring cloud)微服务篇-参考回答
  • 校园综合数据分析可视化大屏 -Vue纯前端静态页面项目
  • JavaScript字符串详解
  • 2025:AI狂飙下的焦虑与追问
  • 【数据分享】黑龙江省黑土区富锦市土地利用数据
  • 【C#补全计划】多线程
  • GitLab CI/CD、Jenkins与GitHub Actions在Kubernetes环境中的方案对比分析
  • 基于SpringBoot的在线拍卖系统,免费附源码
  • JMeter(入门篇)
  • java基础(十)sql的mvcc
  • WebSocket--精准推送方案(二):实时消息推送-若依项目示例
  • 本地处理不上传!隐私安全的PDF转换解决方案
  • java_spring boot 中使用 log4j2 及 自定义layout设置示例
  • Ansible 管理变量和事实
  • 计算机毕设选题推荐-基于大数据的全面皮肤病症状数据可视化分析系统【Hadoop、spark、python】
  • 麒麟V10静默安装Oracle11g:lsnrctl、tnsping等文件大小为0的解决方案
  • Android 对话框 - 基础对话框补充(不同的上下文创建 AlertDialog、AlertDialog 的三个按钮)
  • Pandas数据结构详解Series与DataFrame