ant tree删除节点_Chapter 10 : B-Tree

1. 为什么需要B-Tree?

现代计算机的存储器系统是一个具有不同容量、成本和访问时间的存储设备的层次结构。

磁盘访问相比于内存访问是一个非常耗时的操作,若内存访问需要1秒,则一次磁盘访问就相当于1天,所以我们需要尽量减少磁盘访问的次数。

另一方面,在对磁盘进行访问时,通常都是以页或块为单位进行的,我们从磁盘中读一个字节和读一页的时间是差不多的。

多级存储系统中使用B-Tree,可针对外部查找,大大减少I/O次数。

那么平衡二叉树能否的需求?

假设有n = 1G个记录,每次查找需要进行log2(10^9) = 30次I/O操作,每次只读出一个关键码,得不偿失。

而B-Tree充分利用外存对批量访问的高效支持,将此特点转化为优点,每下降一层,都以超级节点为单位,读入一组关键码。

假如上述每个超级节点中有m = 256个关键码,则log256(10^9) = 4,大大减少了IO的次数。

2. B-Tree的结构

B-Tree是平衡的多路搜索树

c449590aa1a009ed7f63308b1aacfac8.png
  • d代合并为超级节点
  • m = 2^d路
  • m-1个关键码
  • 逻辑上与BBST完全等价

B-Tree节点:

26525d21e6af1d23aac9d6217f1b78e7.png

B-Tree节点内部主要包括两部分:

  • 一组关键码
  • 一组指向孩子的指针

其中,关键码的个数总比指向孩子指针的个数少1

0c14b9091e08865d8bc8bacc1fbb04aa.png

B-Tree的紧凑表示:

abc9a57b6b625103ec40335257f3be8b.png

m阶B-Tree的节点分支数需要满足一定的条件:

  • 2 <= 根节点分支数 <= m
  • ceil(m/2) <= 其他节点分支数 <= m

B-Tree节点的分支数 = 关键码个数+1,所以m阶B-Tree节点的关键码个数需要满足条件:

  • 1 <= 根节点关键码个数 <= m-1
  • ceil(m/2) - 1 <= 其他节点关键码个数 <= m-1

3. B-Tree的查找

93c8b8264d05e9c7bf91cd571ff0bb36.png

B-Tree的查找由一系列的磁盘I/O操作和内存操作组成,每深入一层进行一次磁盘I/O,所以算法的运行时间主要取决于磁盘I/O次数,算法时间复杂度为O(logn)

4. B-Tree的插入

B-Tree的插入三部曲:

  • 查找:在当前B-Tree中查找待插入关键码,得到待插入的超级节点
  • 插入:在待插入超级节点中插入关键码
  • 分裂:如果超级节点关键码个数超过上限,则执行分裂操作

算法:

// from THU-dsacpp
bool BTree<T>::insert( const T & e ) {
    BTNodePosi(T) v = search( e );
    if ( v ) return false; //确认e不存在
    Rank r = _hot->key.search( e ); //在节点_hot中确定插入位置
    _hot->key.insert( r+1, e ); //将新关键码插至对应的位置
    _hot->child.insert( r+2, NULL ); _size++; //创建一个空子树指针
    solveOverflow( _hot ); //若上溢,则分裂
    return true; //插入成功
}

算法主要步骤:

  • 算法首先调用B-Tree的成员函数search查找关键码e
  • 这里规定B-Tree中的关键码不重复,所以如果e存在直接返回false
  • 如果e不存在,_hot表示上一个访问的超级节点,而查找e失败于外部节点,此时_hot就表示关键码e待插入的叶节点
  • 随后在_hot节点的关键码中插入e,在指向孩子的指针向量中插入NULL
  • 最后调用solveOverflow函数,处理上溢(如果有的话)

分裂

主要思想:以上溢节点关键码的中位数s为界,将原节点划分左右两个孩子节点,将s提升一层

05a00745fac8f10cb26e01a65aa895b9.png

df137cfc6c274e9755e2b4071b06ae5f.png

5. B-Tree的删除

B-Tree的删除四部曲:

  • 查找:首先在B-Tree中查找待删除关键码,得到待删除关键码所处的超级节点v
  • 替换:如果v不是叶节点,则找关键码的直接后继(先到右子树,再一路向左),并将关键码与叶节点的第一个关键码替换
  • 删除:删除叶节点中的关键码
  • 旋转或合并:如果删除后叶节点发生下溢,则执行旋转或合并操作

93213658013456896db46253c2fa36c9.png

旋转

旋转操作的主要思想:发生下溢的节点“左顾右盼”,如果兄弟节点的关键码足够多,则从兄弟节点中“借来”一个关键码。

c3381049233292de3a33f3d59c4836ff.png

合并

3941e72a3ad6a1056c32ecb025fbd697.png

L节点为何恰含有ceil(m/2) -1个关键码?

如果多于ceil(m/2)-1,则可以执行旋转操作;如果少于ceil(m/2)-1,则L自身已经发生下溢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值