1.2磁盘存储链式的B树与B+树

B树和B+树是平衡树的一种,在数据库、文件系统等大规模存储系统中广泛应用,主要用于实现高效的查找、插入和删除操作。它们都具有自平衡的特性,能够在最坏情况下提供对数时间复杂度的操作。

1. B树(B-Tree)
定义

B树是一种自平衡的多路查找树,它将数据存储在节点中并按顺序排列。B树的每个节点可以包含多个子节点和多个元素,因此它在存储大量数据时非常高效。

性质
  • 每个节点可以有多个子节点:B树的每个节点不仅有一个数据项,而且可以有多个子节点,允许节点有多个键值。
  • 节点的键值按顺序排列:节点内部的键值是有序的,从左到右逐渐增大。
  • 根节点至少有两个子节点(除非是空树),其他节点至少有 ⌈m/2⌉ 个子节点,其中 m 是树的阶数。
  • 节点的键数限制:一个节点最多包含 m - 1 个键,最少包含 ⌈m/2⌉ - 1 个键。
  • 查找效率:B树的查找操作从根节点开始,依次向下查找子树,时间复杂度为 O(log n),其中 n 为树中的元素个数。
  • 插入与删除操作:插入和删除操作保持树的平衡,当节点满时,会分裂节点;当节点键值过少时,会进行合并操作。
  • 树的高度相对较低:由于每个节点包含多个键,B树的高度通常比较低,因此查找和操作效率较高。
适用场景
  • 数据库索引:B树适用于大规模存储数据,广泛应用于数据库和文件系统中的索引结构。
  • 磁盘存储:由于B树具有较高的存储密度和较少的树高,它非常适合磁盘存储系统,减少了磁盘I/O操作的次数。
cpp 复制代码
#define SUB_M    3


typedef struct _btree_node {
    
    int *keys; // int keys[2 * SUB_M - 1];  5
    struct _btree_node **childrens; //struct _btree_node *childrens[2 * SUB_M - 1]; 6
    
    int num;
    int leaf;
    
}btree_node;


typedef struct _btree {
    
    struct _btree_node *root;
}
2. B+树(B+ Tree)
定义

B+树是B树的变种,B+树的所有值都存在叶子节点,并且叶子节点通过链表连接。它与B树的不同之处在于,B+树的内部节点只存储键值,不存储实际数据,所有数据只存在叶子节点。

性质
  • 所有值都存在叶子节点:B+树的非叶子节点只包含键值,实际的数据值只存储在叶子节点中。
  • 叶子节点通过链表连接:所有叶子节点组成一个链表,这使得B+树的范围查询非常高效。可以通过叶子节点之间的链表快速访问范围内的数据。
  • 内部节点只存储键值:B+树的非叶子节点只存储键值信息,并不存储数据,简化了节点的存储结构。
  • 与B树相比,B+树的查询效率较高:因为数据存储在叶子节点并且叶子节点形成链表,所以在范围查询时,B+树可以通过链表进行顺序访问,提高了范围查询的效率。
  • 插入与删除:B+树的插入和删除操作与B树类似,都是通过节点分裂和合并来保持树的平衡。由于内部节点不存储数据,B+树的插入和删除操作通常较为高效。
  • 树的高度:B+树的高度通常和B树相同,因为它们的阶数和高度结构是一样的。
适用场景
  • 数据库索引:B+树是现代数据库管理系统中最常用的索引结构,因为它在范围查询和顺序扫描方面更具优势。常见的数据库系统如 MySQL、Oracle 等都使用 B+ 树作为索引结构。
  • 文件系统:文件系统中的目录结构、文件的查找、顺序读取等操作通常采用 B+ 树来组织数据。
  • 磁盘和SSD存储:由于数据和指针的分离,B+树在磁盘或SSD上能够更有效地减少I/O操作,适合大规模的数据存储和访问。
3.B-树的删除

先合并在删除

先借位在删除

cpp 复制代码
#define SUB_M    3


typedef struct _btree_node {
    
    int *keys; // int keys[2 * SUB_M - 1];  5
    struct _btree_node **childrens; //struct _btree_node *childrens[2 * SUB_M - 1]; 6
    
    int num;
    int leaf;
    
}btree_node;


typedef struct _btree {
    
    struct _btree_node *root;
}btree;


// 创建结点
btree_node *btree_create_node(int leaf) {

    btree_node *node = (btree_node*)calloc(1, sizeof(btree_node));
    if (node == NULL) return NULL;

    node->leaf = leaf;
    node->keys = calloc(2 * SUB_M - 1, sizeof(int));
    node->childrens = (btree_node**)calloc(2 * SUB_M, sizeof(btree_node*));
    node->num = 0;

    return node;
}
// 删除节点
void btree_destroy_node(btree_node *node) {
    free(node->childrens);
    free(node->keys);
    free(node);    
}
// 分裂
void btree_split_child(btree *T, btree_node *x, int idx) {

    btree_node *y = x->childrens[idx];
    btree_node *z = btree_create_node(y->leaf);

    //// 对z操作
    z->num = SUB_M - 1;

    int i = 0;
    for (i = 0; i < SUB_M-1; i++) {
        z->keys[i] = y->keys[SUB_M + i];
    }
    
    if (y->leaf == 0) { //inner内结点
        for (i = 0; i < SUB_M; i++) {
            z->childrens[i] = y->childrens[SUB_M + i];
        }
    }
    
    ////对y操作
    y->num = SUB_M - 1;
    for (i = x->num; i >= idx + 1; i--) {
        x->childrens[i + 1] = x->childrens[i];
    }
    x->childrens[idx + 1] = z;

    for (i = x->num-1; i >= idx; i--) {
        x->keys[i+1] = x->keys[i];
    }
    x->keys[idx] = y->keys[SUB_M - 1];
    x->num += 1;
    
}

//插入操作
void btree_insert(btree *T, int key) {

    btree_node *r = T->root;
    
    if (r->num == 2 * SUB_M - 1) {
        
        btree_node *node = btree_create_node(0);
        T->root = node;

        node->childrens[0] = r;

        btree_split_child(T, node, 0);       
    } 
}

//合并操作
void btree_merge(btree *T, btree_node *x, int idx) {

    btree_node *left = x->childrens[idx];
    btree_node *right = x->childrens[idx+1];

    int i = 0;

    /////data merge
    left->keys[left->num] = x->keys[idx];
    for (i = 0;i < right->num; i++) {
        left->keys[SUB_M + i] = right->keys[i];
    }
    if (!left->leaf) {
        for (i = 0;i < SUB_M; i++) {
            left->childrens[SUB_M + i] = right->childrens[i];
        }
    }
    left->num += right->num + 1; // 合并键数应该是左节点数量 + 右节点数量 + 1(来自父节点的键)

    //destroy right
    btree_destroy_node(right);

    //node 
    for (i = idx+1; i < x->num; i++) {
        x->keys[i-1] = x->keys[i];
        x->childrens[i] = x->childrens[i+1];
    }
    x->childrens[i+1] = NULL;
    x->num -= 1;

    if (x->num == 0) {
        T->root = left;
        btree_destroy_node(x);
    }
}

参考链接:0voice · GitHub

相关推荐
TechNomad7 小时前
排序算法:希尔排序算法
数据结构·算法·排序算法
im_AMBER7 小时前
Leetcode 83 使数组平衡的最少移除数目中等相关标签 | 尽可能使字符串相等
数据结构·c++·笔记·学习·算法·leetcode
先生沉默先7 小时前
c#Socket学习,使用Socket创建一个在线聊天,需求分析与创建项目,数据结构创建(1)
数据结构·学习·c#
Bdygsl7 小时前
数据结构 —— 顺序表
数据结构·链表
(❁´◡`❁)Jimmy(❁´◡`❁)7 小时前
F - Manhattan Christmas Tree 2
数据结构·算法
良木生香8 小时前
【数据结构-初阶】顺序表相关习题
数据结构
小龙报8 小时前
【初阶数据结构】从 “数组升级” 到工程实现:动态顺序表实现框架的硬核拆解指南
c语言·数据结构·c++·算法·机器学习·信息与通信·visual studio
kesifan8 小时前
数据结构栈和队列
数据结构
TrueFurina(互关互赞)8 小时前
7-4 区间水仙花数 Python程序设计-MJU实验四(编程入门•多代码实现•测试均通过)
数据结构·算法·飞书·创业创新·学习方法·远程工作·改行学it
2301_789015628 小时前
每日精讲:环形链表、两个数组中的交集、随机链表的复制
c语言·数据结构·c++·算法·leetcode·链表·排序算法