C/C++Linux服务器开发 一、磁盘存储链式的B树与B+树

2023-05-16

在前一篇博客中我们分析了“随处可见的红黑树”,相信大家都有了一定的了解。想了解的朋友可以去上面瞅瞅呢。而今天我们就要介绍适合磁盘存储的B树。b树的介绍、以及性质网上有很多,不是很了解得可以先找找,要知道B树的阶以及度,以及子树的性质,这里我们只对设计有个介绍。

1.B树的定义

多叉树等于B树,一颗M阶B树T,满足以下条件:
1 每个结点至少拥有M颗子树
2 根结点至少有两颗子树。
3 除根结点外,其余的每个分支结点至少拥有M/2颗子树。
4 所有叶子结点都在同一层==》保证平衡树
5 有k课子树的分支结点,则存在k-1个关键字,关键字按照递增进行排序。
6 关键字数量满足 ceil(M/2) -1 <= n <= M-1
实现设计时候
//度:t
//阶:2t
//结点最大元素: 2t-1

不了解度和阶的要先理解清楚,以及子树关系个数

2.B树的数据结构

typedef int KEY_TYPE;

//根据b树的性质进行定义
typedef struct _btree_node{
    struct _btree_node **children;//子树
    KEY_TYPE *keys;       //定义指针用于存储key

    int num;    //判断key的数量
    int leaf;   //用来判断当前节点是否是叶子节点 1:yes,0:no


}btree_node;

typedef struct _btree{
    btree_node * root;
    int t; //表示度:一个结点含有的子节点的个数

}btree;

3.创建结点


//创建节点
struct btree_node *btree_create_node(int t,int leaf)
{
    btree_node *node = (btree_node *)calloc(1,sizeof( btree_node));
    if(node == NULL){
        return NULL;
    }
    node->num = 0;
    node->keys = (KEY_TYPE *)calloc(1,(2 * t -1)*sizeof(KEY_TYPE)); //最多的key内存
    node->children = (btree_node **)calloc(1,2 * t *sizeof(btree_node *));//的子节点内存
    node->leaf = leaf;

    return node;

}

 4.销毁结点

//销毁节点
void btree_destroy_node( btree_node *node)
{
    if(node)
    {
        if(node->keys)
        {
            free(node->keys);
        }
        if(node->children)
        {
            free(node->children);
        }
        free(node);
    }
}

5.b树的创建

//b树的创建
void btree_create(btree *T,int t)
{
    T->t = t;
    struct btree_node *x = btree_create_node(t,1);//1为是根节点,0不是
    T->root = x;
}

6.b树的插入

//b树的插入
void btree_insert(btree *T,KEY_TYPE key)
{
     btree_node *root = T->root;
    if(root->num == 2 * T->t -1) //根结点的数量满了
    {
        btree_node *node = btree_create_node(T->t,0);
        T->root = node;

        node->children[0]  = root;
        btree_split_child(T,node,0);//分裂
    }else{
        btree_insert_nofull(T,root,key);//直接插入
    }
}

将b树的插入代码贴出来,然后我们分析下插入的流程如下所示

 我们需要添加L,我们是想将L加在最后面位置,我们先要判断结点数量是否满了,就是代码上的


if(root->num == 2 * T->t -1),因为我们需要满足B树定义的性质,这个B树的度是3,所以最少的key数量为2,最多可以为5,而GHIJK已经五个,现在添加了L后明显超出key最大数量,此时我们需要分裂它  

7.B树的分裂(根结点满了)

还是以上图为例子,我们先定义一个空结点Z,将JK放入进去,将I上移到CF后面,再将Z放入到I的children中,如下代码实现分为1,2,3三个步骤。


//b树的分裂
void btree_split_child(btree *T,btree_node *x,int i)
{
    btree_node *y = x->children[i];
    btree_node *z = btree_create_node(T->t,y->leaf);


    //1.将J和K放入到Z结点中
    int j = 0;
    for(j = 0; j < T->t -1;j++)
    {
        z->keys[j] = y->keys[j+T->t];
    }
    if(y->leaf == 0)
    {
        for(j = 0;j < T->t;j++){
            z->children[j] = y->children[j + T->t];
        }
    }

    //2.将Y的key数量减1
    y->num = T->t - 1;

    //3.将y放入x中
    for(j = x->num;j>= i+1;j--)
    {
        x->children[j+1] = x->children[j];
    }
    x->children[i+1] = z;

    for(j = x->num -1;j>=i ;j--)
    {
        x->keys[j+1] = x->keys[j];
    }
    x->keys[i] = y->keys[T->t -1];
    x->num += 1;

}

以上是根结点满的情况下的使用,如果根结点不满呢直接使用btree_insert_nofull(T,root,key);//直接插入

8.根结点不满


//插入不满的结点
void btree_insert_nofull(btree *T,btree_node *x,KEY_TYPE key)
{
    int i = x->num - 1;
    if(x->leaf) //如果是叶子节点
    {
        while (i >= 0 && x->keys[i] > key) {
            x->keys[i +1] =  x->keys[i] ;
            i--;
        }
        x->keys[i + 1]  = key;
        x->num += 1;

    }else{//如果不是叶子节点
        while(i >= 0 && x->keys[i] >key) i--;
        if(x->children[i + 1]->num == 2*T->t-1)
        {
            btree_split_child(T,x,i);
            if(key > x->keys[i+1]) i++;
        }
        btree_insert_nofull(T,x->children[i+1],key);
    }
}

根结点不满的时候,我们又得考虑两种情况,1.如果我们插入的刚好是叶子节点,此时我们不用考虑子节点,直接将值插入进来,2.如果不是叶子节点,我们需要判断孩子节点是否满了,如果满了,继续分裂,之后我们再递归查询。至此插入分裂结束了。

结点的删除涉及到借位,合并,在下才疏学浅,只能简单介绍下

 至于删除合并的部分没有研究明白,等后面有时间了再来继续,但这里可以提供一份完全可用的插入、删除的B树代码。

代码链接:c/c++Linux服务器开发B树的建立-C/C++文档类资源-CSDN下载

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C/C++Linux服务器开发 一、磁盘存储链式的B树与B+树 的相关文章

  • IMU 测量模型和运动学模型

    一 概念 高斯白噪声 测量噪声是AD转换器件引起的外部噪声 xff0c 波动激烈的测量白噪声 随机游走 这里指零偏Bias 随机游走噪声 xff0c 是传感器内部机械 温度等各种物理因素产生的传感器内部误差的综合参数 xff0c 是变化缓慢
  • java参数校验注解

    java参数校验注解 java中前后台参数传递时如何对参数进行校验 校验主要使用到 javax validation类 一 引入依赖 SpringBoot的web组件中已引入validation的jar包 xff0c 但也可自行引入 spa
  • SpringBoot集成阿里easyexcel(三)CellWriteHandler图片转换

    继承单元格处理器 xff0c 通过重写不同方法 xff0c 对单元格进行处理 span class token keyword public span span class token keyword class span span cla
  • 使用Mybatis-plus拦截加密数据

    使用Mybatis plus拦截加密数据 使用自定义注解来标识需要加密的po和字段 xff0c 并通过mybaitsplus的插件工具类Interceptor类来实现对数据的拦截与加密转换操作 一 自定义加密注解 作用在类上的注解 pack
  • SpringBoot集成阿里easyexcel(四)Converter导入导出数据转换器

    SpringBoot集成阿里easyexcel xff08 四 xff09 Converter导入导出数据转换器 通过com alibaba excel converters Converter转换器实现Excel导入导出时Java数据与E
  • SpringBoot集成Ehcache缓存

    SpringBoot集成Ehcache缓存 Ehcache有两种缓存方式 xff0c 分别是堆内存 磁盘 xff08 非堆内存 xff09 一 堆内存缓存 也就是MemoryStore xff0c 速度最快 xff0c 不适合存放大量数据
  • Spring的切面编程(AOP)概念与使用AOP实现日志记录

    Spring的切面编程 xff08 AOP xff09 概念与使用 一 面向切面编程 定义 面向切面编程 xff08 AOP xff09 是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术 作用 xff1a 利用AOP对业务
  • 关于intrins.h头文件的介绍

    在单片机中应用最多的当然就是移位函数 xff0c 利用移位函数可以更简便的实现流水灯等效果 移位函数 移位函数名 左移 span class token function crol span span class token punctua
  • 大批量数据分批批量插入或更新(Mybatis+MySQL)

    大批量数据分批批量插入或更新 在MySQL数据库的前提下 xff0c 插入或更新大批量数据 首先批量插入需要考虑到以下几个因素 xff1a 数据库一次可以承受多大或者多少条数据的插入批量插入是否会占用Mysql资源太久 xff0c 影响系统
  • VSCode配置C++开发环境

    更新细节 2020 7 3 更新细节及排版 2022 6 9 昨天从下午一直研究到晚上十一点 xff0c 查阅了很多博客资料 xff0c 还是没配置好VSCode的C 43 43 开发环境 xff0c 今天早上又弄了一下 xff0c 现在O
  • stm32模拟输出PPM信号

    PPM信号周期为20ms xff0c 分成10分代表10个通道信号 xff0c 也就是2ms代表一个信号 0 5ms代表一个通道信号的开始 xff0c 所以0 5ms 2ms为通道范围控制 LED p1 39 A 39 8 IO口初始化 x
  • 使用JSON.parse,解决ie6-7上JSON未定义问题

    使用JSON parse时出现JSON未定义问题 xff0c JSON不是标准的javascript类型 xff0c 一些高级的浏览器支持 xff0c 但一些老一点的浏览器不支持JSON 如ie6 7 若需要 ie6 7 支持JSON只需要
  • C语言中的大小端转换与高低位颠倒

    在说大小端高低位之前 xff0c 肯定要说明数据在计算机内是如何存储的 在计算机中 xff0c 我们将数据分割成了一个一个的字节 xff08 byte xff09 xff0c 而每个字节又有8位 xff08 bit xff09 一个字节 x
  • C语言库函数中的Strcat函数

    一 Strcat函数的参数 Strcat函数所引用的头文件是 lt string h gt char strcat char strDestination const char strSource 参数说明 xff1a strDestina
  • SLAM中的marginalization 和 Schur complement

    在视觉SLAM的很多论文中 xff0c 会大量或者偶尔出现marginalization这个词 翻译为边缘化 xff0c 有的论文是特地要用它 xff0c 比如sliding window slam 2 okvis 3 dso 4 而有的论
  • 数据结构之单链表循环

    单链表循环代码如下 xff1a include lt stdio h gt include lt stdlib h gt typedef struct node int data struct node next sqlist sqlist
  • 数据结构之双链表循环

    定义是 xff1a 每个数据结点都有两个指针 xff0c 分别指向直接后继和直接前驱 因此双向链表中单任意一个结点开始 xff0c 都可以很方便的访问它的前驱结点和后继结点 循环链表指 xff1a 最后一个结点next指向头结点 xff0c
  • linux学习之进程

    进程概念 xff1a 活跃度程序 xff0c 占用系统资源 xff0c 在内存中执行产生一个进程 孤儿进程 xff1a 父进程先于子进程结束 xff0c 则子进程称为孤儿进程 xff0c 并且这个子进程被init进程回收 include l
  • 使用libcurl实现http通信——post上传数据并获取response

    接口释义 使用libcurl实现http通信 get获取response 代码实现 size t span class token function responseStr span span class token punctuation
  • C语言学习之sprintf

    sprintf函数介绍 xff1a 该函数原型为 xff1a int sprintf char str const char format 该函数的功能为 xff1a 本该输出到显示上的数据 xff0c 改为输出到str所指导内存空间中 x

随机推荐