【复习笔记】B树、B+树

一、二分查找

当序列分布较为均匀时效率高

int bin_search(vector<int> &nums, int key){
    int low = 0;
    int high = nums.size() - 1;
    while(low <= high){
        int mid = (low + high) / 2;
        if(nums[mid] < key){
            low = mid + 1;
        }else if(nums[mid] > key){
            high = mid - 1;
        }else{
            return mid; 
        }
    }
    return -1;
}
二、插值查找

当查找的序列非常极端时效率高,比如在序列:1,2,4,6,7,9,11,12,13,999,1000中查找999,若是用二分查找效率就很低了,需要查找3次。若用插值查找就只需要查找1次就行了。当数据非常大且极端时,插值查找的效率就体现得非常明显

int insert_search(vector<int> &nums, int key){
    int low = 0;
    int high = nums.size() - 1;
    while(low <= high){
    	//因为除法会向下取整,所以mid的计算结果不会越界
        int mid = low + (high-low)*(key-nums[low])/(nums[high]-nums[low]);
        if(nums[mid] < key){
            low = mid + 1;
        }else if(nums[mid] > key){
            high = mid - 1;
        }else{
            return mid; 
        }
    }
    return -1;
}
三、分块查找

在块内无序,块间有序的顺序表中查找元素。
在这里插入图片描述
首先需要建立索引表,索引表的每个元素记录每个分块的最大关键字和分块的存储区间。索引表元素数据结构如下:

typedef struct{
    ElemType maxValue;//块内最大值
    int low;
    int high;
}Index;

分块查找算法过程:

  1. 在索引表中确定待查值所属的分块(可顺序,可折半)
  2. 在块内顺序查找

注:对索引表进行折半查找时,若索引表中不包含目标关键字,则折半查找最终停在 l o w < h i g h low<high low<high,要在 l o w low low所指分块中查找

在这里插入图片描述
当对顺序表中的元素进行插入或删除的时候,除了顺序表中元素都要移动以外,还需要修改索引表元素的数据。效率太低,一般的我们可以改进为链式存储,如下:

在这里插入图片描述
插入元素时,只需要挂在最后即可。删除元素时,修改指针即可。

四、B树

在这里插入图片描述
基本概念:

  1. 终端结点: 最下层含有实际数据的结点
  2. 叶子结点: 最下层表示空值的结点
  3. B树的阶: B树中所有结点的孩子个数的最大值称为B树的阶

一棵m阶B树或为B树,或为满足以下特性的m叉树:

  1. 树中每个结点最多有 m m m棵子树,即至多含有 m − 1 m-1 m1关键字
  2. 若根结点不是终端结点,至少有两棵子树(包含在绝对平衡里)
  3. 除了根结点外的所有非叶结点至少有 ⌈ m / 2 ⌉ \lceil m/2 \rceil m/2棵子树,即至少含有 ⌈ m / 2 ⌉ − 1 \lceil m/2 \rceil-1 m/21个关键字。(每个结点尽可能存满,树不会太深)
  4. 所有的叶结点都在同一层次上,这些结点都代表空
  5. 对于任何一个非叶结点,左右子树高度相同,即绝对平衡
  6. 对于任何一个非叶结点中的任何一个元素,左指针所指块包含元素<该元素<右指针所指块包含元素,类似于排序树

在这里插入图片描述

5叉排序树结点的定义
struct Node{
    ElemType keys[4];         //最多4个关键字
    struct Node* child[5];    //最多5个孩子
    int high;                 //结点中关键字数量
};

含有n个关键字的m叉B树,最小高度和最大高度
在这里插入图片描述

最小高度——让每个结点尽可能满,有 m − 1 m-1 m1个关键字, m m m个分叉,则有:
n ≤ ( m − 1 ) ( 1 + m 2 + m 3 + . . . + m h − 1 ) = m h − 1 n\leq(m-1)(1+m^2+m^3+...+m^{h-1})=m^h-1 n(m1)(1+m2+m3+...+mh1)=mh1,因此
h ≥ l o g m ( n + 1 ) \qquad\qquad\qquad\qquad\qquad h\ge log_m(n+1) hlogm(n+1)

最大高度——让每层分叉尽可能少,即根结点只有2个分叉,其他结点只有 ⌈ m / 2 ⌉ \lceil m/2 \rceil m/2个分叉,每层结点至少有:第一层1、第二层2、第三层 2 ⌈ m / 2 ⌉ 2\lceil m/2 \rceil 2m/2…第 h h h 2 ( ⌈ m / 2 ⌉ ) h − 2 2(\lceil m/2 \rceil)^{h-2} 2(m/2)h2。则第 h + 1 h+1 h+1层共有叶子结点(失败结点): 2 ( ⌈ m / 2 ⌉ ) h − 1 2(\lceil m/2 \rceil)^{h-1} 2(m/2)h1

由于 n n n个关键字的B树必有 n + 1 n+1 n+1个结点,则 n + 1 ≥ 2 ( ⌈ m / 2 ⌉ ) h − 1 n+1\ge2(\lceil m/2 \rceil)^{h-1} n+12(m/2)h1,即
h ≤ l o g ⌈ m / 2 ⌉ n + 1 2 + 1 \qquad\qquad\qquad\qquad\quad h\le log_{\lceil m/2 \rceil}\frac{n+1}{2}+1 hlogm/22n+1+1

B树的插入操作
1.结点分裂

在这里插入图片描述
在插入 k e y key key后,若导致原结点关键字数超过上限,则从中间位置( ⌈ m / 2 ⌉ \lceil m/2 \rceil m/2)将其中的关键字分为两部分,左部分包含关键字放在原结点中,右部分关键字放在新结点中,中间结点成为两者的父结点,分裂结果如下:
在这里插入图片描述

插入88、90、99

在这里插入图片描述
接着分裂
在这里插入图片描述
插入70、83、87
在这里插入图片描述
接着分裂
在这里插入图片描述
插入92、93、94,分裂完成后

在这里插入图片描述
插入73、74、75
在这里插入图片描述
分裂终端结点
在这里插入图片描述
此时可以看到根结点关键字太多了,需要分裂,按照同样的道理,分裂结果如下:
在这里插入图片描述

对于分裂操作的总结:
  1. 对m阶B树,除根结点外,结点关键字个数 ⌈ m / 2 ⌉ − 1 ≤ n ≤ m − 1 \lceil m/2 \rceil-1\le n\le m-1 m/21nm1
  2. 对于所有的结点,左子树 < 根结点 < 右子树
  3. 新的元素一定插入到终端结点
    在这里插入图片描述
B树的删除操作

现有如下的B树:
在这里插入图片描述
删除60后:
在这里插入图片描述
注:若待删除的关键字处于终端结点,则直接删除该关键字。同时还需检查结点关键字个数是否满足 ⌈ m / 2 ⌉ − 1 ≤ n ≤ m − 1 \lceil m/2 \rceil-1\le n\le m-1 m/21nm1

删除80,此时根结点为空,可以利用当前关键字的直接前驱直接后继填补根结点

直接前驱: 当前关键字左子树“最右下”的元素,即左子树最大的关键字
直接后继: 当前关键字右子树“最左下”的元素,即右子树最小的关键字

下面利用直接后继填补根结点
在这里插入图片描述
注:删除非终端结点80的操作,转换成了删除终端结点80的操作。故对非终端结点关键字的删除,必然可以抓换为对终端结点关键字的删除

接着,我们删除关键字38,删除结果如下:
在这里插入图片描述
可以看到,就是直接把38干掉,70提上去,49填下来,分别补到对应的位置

注:当右兄弟有充足的关键字时,用当前结点的后继(49),和后继的后继(70) 来填补

接下来,删除90,删除结果如下:在这里插入图片描述
同理,就是直接把90干掉,88填下来,87提上去,分别补到对应的位置

注:当左兄弟有充足的关键字时,用当前结点的前驱(88),和前驱的前驱(87) 来填补

接着删除49,先干掉49,结果如下:
在这里插入图片描述
此时,对于最坐下的结点,只有25这一个关键字,而右兄弟又没有多余的关键字借给他。现在,我们将关键字25、70、71、72合并,结果如下:
在这里插入图片描述
然而,此时关键字73所在的结点不符合B树的特性,我们将73、82、87、93合并,结果如下:
在这里插入图片描述
注:兄弟不够借时,则将关键字删除后的结点与左(或右)兄弟结点,以及父结点中的关键字合并

在这里插入图片描述
总结:
在这里插入图片描述

五、B+树

在这里插入图片描述
B树与B+树对比

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
而B树中,所有结点的关键字 互不重复


总结:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值