B树的C语言实现

前言

    今天我们再来学习另外一种高级数据结构B树,我们知道树的查询时间复杂度和其树的高度有直接关系,当我们向红黑树里面插入大量的数据时,有两个问题:

(1)首先,内存是有限的不可能无止境的一直插入数据,而基于BST的平衡树如AVL树和红黑树,本质上都是基于内存的数据结构。

(2)如果将AVL树,红黑树或者跳跃表直接存储到磁盘上,然后用来检索可以吗? 答案是可以的,但问题是基于磁盘寻道查询比基于内存慢太多了,举个例子,假设现在有100万数据分布在红黑树里面,按照红黑树的平均查找性能O(logN)来计算,在N=100万时,检索任意数据平均需要20次查询,如果是在内存完全没问题,但此时红黑树是如果存在磁盘上,那就完全不一样了,按照普通硬盘或者文件系统,每次查询IO一次总耗时约10毫秒计算,那么在百万级别的数据量下,检索一次数据就需要10*20,大概就是0.2秒,假如现在数据量扩大100倍,数据总量是一亿,那么检索一次数据就需要20秒,这个性能是完全不能接受的,可以想象在这种情况下,使用二叉树是不合适的。

    正是由于描述的问题,所以迫切需要一种面向磁盘或者文件系统友好的数据结构,而它就是B树,或者基于B树的扩展B+,B*树等。上面问题的根源在于树的高度太高,导致查询外存,也就是访问磁盘IO次数太多,从而大大拖慢了检索性能,那么思路就清晰了,只要想法子降低树的高度就可以了,没错B树就是这么一种m叉的多路平衡树,你可以想象它的孩子节点少则2个,多则数千个,所以就从二叉树的廋高,变成了多叉树的矮胖,正是这样才大大降低了树的高度,从而使得这种数据结构更适合存储在磁盘上,并且充分了利用了磁盘的块的预读机制(局部性访问原理),通过缓存的方式进一步提升性能,磁盘在读取某一个文件指针的时候,通常会把紧挨着的数据,也全部读到缓存,因为实践证明,当一个文件数据被访问的时候,它周边的数据很快也会被访问,这里简单说下磁盘扇区,磁盘块,磁盘也的区别:

扇区:磁盘的最小存储单位;

磁盘块:文件系统读写数据的最小单位;

页:内存的最小存储单位;

磁盘块和页的大小一般情况下为4KB,所以在B树中一个节点的最大存储数据个数的总大小一般不能超过4KB。

基于B树的结构充分利用了这一点,从而非常适合做文件系统或者数据库的索引。

B-树的性质


一颗M阶B树T,满足以下条件
1. 每个结点至多拥有M棵子树
2. 根结点至少拥有两棵子树
3. 除了根结点以外,其余每个分支结点至少拥有M/2棵子树
4. 所有的叶结点都在同一层上
5. 有k棵子树的分支结点则存在k-1个关键字,关键字按照递增顺序进行排序
6. 关键字数量满足ceil(M/2)-1 <= n <= M-1

下面咱们以一棵5阶(M=5,即除根结点和叶子结点之外的内结点最多5个孩子,最少3个孩子)B树实例进行讲。

插入(insert)操作

  1. 插入一个元素时,首先在B树中是否存在,如果不存在,即在叶子结点处结束,然后在叶子结点中插入该新的元素,注意:
  2. 如果叶子结点空间足够,这里需要向右移动该叶子结点中大于新插入关键字的元素,如果空间满了以致没有足够的空间去添加新的元素,则将该结点进行“分裂”,将一半数量的关键字元素分裂到新的其相邻右结点中,中间关键字元素上移到父结点中(当然,如果父结点空间满了,也同样需要“分裂”操作),而且当结点中关键元素向右移动了,相关的指针也需要向右移。
  3. 如果在根结点插入新元素,空间满了,则进行分裂操作,这样原来的根结点中的中间关键字元素向上移动到新的根结点中,因此导致树的高度增加一层。

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
B+是一种常用的数据结构,常用于在磁盘存储的大型数据集合中进行索引。它是一种多叉,具有以下特征: 1. 每个节点最多有M个子节点(M >= 2)。 2. 除了根节点和叶子节点外,每个节点至少有 ceil(M/2) 个子节点。 3. 所有叶子节点位于同一层,且不存储数据,只存储索引。 4. 所有非叶子节点都不存储数据,只存储索引。 B+实现通常涉及到以下几个操作: 1. 插入节点:将新节点插入到正确的位置上,并进行必要的平衡操作。 2. 删除节点:将指定节点删除,并进行必要的平衡操作。 3. 查找节点:从根节点开始遍历,根据索引值确定子节点,直到找到目标节点或者到达叶子节点。 C语言实现B+需要定义一个节点结构体,包含如下成员变量: ``` typedef struct node_t { int is_leaf; // 是否为叶子节点 int n; // 当前节点关键字个数 int keys[M-1]; // 关键字数组 void *data[M-1]; // 数据指针数组 struct node_t *p[M]; // 子节点指针数组 struct node_t *next; // 叶子节点下一个节点指针 } node_t; ``` 其中,is_leaf表示该节点是否为叶子节点,n表示该节点当前存储的关键字个数,keys和data数组分别存储关键字和数据指针,p数组存储子节点指针,next表示叶子节点的下一个节点指针。 在具体实现插入、删除和查找等操作时,需要根据B+的特点进行相应的处理,包括节点的拆分、合并、旋转等操作。具体实现细节可以参考相关的B+算法实现
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值