二十一、B树的定义、查找、插入和删除
一、B树的定义
一棵m阶的B树,或为空树,或为满足下列特性的m叉树:
(1)树中每个结点至多有m棵子树;
(2)B树是所有结点的平衡因子均等于0的多路平衡查找树;
(3)若根结点不是叶子结点,则至少有两棵子树;
(4)除根之外的所有非终端结点至少有⌈m/2⌉棵子树;
(5)所有的叶子结点都出现在同一层次上,并且不带信息,通常称为失败结点(失败结点并不存在,指向这些结点的指针为空。引入失败结点是为了便于分析B树的查找性能);
(6)所有的非终端结点最多有m-1个关键字,结点的结构如图所示。

其中:
- ${K_i}(i = 1,...,n)$ 为关键字,且 ${K_i} < {K_{i + 1}}(i = 1,...,n - 1)$。
- ${P_i}(i = 0,...,n)$ 为指向子树根结点的指针,且指针 ${P_{i - 1}}$ 所指子树中所有结点的关键字均小于 ${K_i}(i = 1,...,n)$ , ${P_{n}}$ 所指子树中所有结点的关键字均大于 ${K_{n}}$。
- $n(\left\lceil {m/2} \right\rceil - 1 \le n \le m - 1)$ 为关键字的个数(或 $n+1$ 为子树个数)。
从上述定义可以看出,对任一关键字 ${K_i}$ 而言, ${P_{i - 1}}$ 相当于指向其“左子树”, ${P_{i}}$ 相当于指向其“右子树”。
B树具有平衡、有序、多路的特点。
二、B树的查找
B树的查找从根结点开始,重复以下过程:若给定关键字等于结点中某个关键字Ki,则查找成功;若给定关键字比结点中的K1小,则进入指针A0。指向的下一层结点继续查找;若在两个关键字Ki-1和Ki之间,则进入它们之间的指针Ai-1从一指向的下一层结点继续查找;若比该结点所有关键字大,则在其最后一个指针An指向的下一层结点继续查找;若查找到叶子结点,则说明给定值对应的数据记录不存在,查找失败。
查看代码
#define m 3 //B树的阶
typedef struct BTNode
{
int keynum; //结点当前关键字个数
KeyType key[m+1]; //关键字数组,key[0]未用
struct BTNode *parent; //双亲结点指针
struct BTNode *ptr[m+1]; //孩子结点指针数组
Record *recptr[m+1]; //记录指针向量,0号单元未用
}BTNode, *BTree;
typedef struct
{
BTree pt; //指向找到的结点
int i; //1<=i<=m,在结点中的关键字位序
int tag; //1:查找成功;0:查找失败
}Result;
int Search(BTree p,int key)
{ //在p->key[1...p->keynum]找k
int i=1;
while(i<=p->keynum && k>p->key[i]) i++;
return i;
}
Result SearchBTree(BTree T,KeyType key)
{ //在m阶B树T上查找关键字key,返回结果(pt,i,tag)
//若查找成功,则特征值tag=1,指针pt所指结点中第i个关键字等于key
//否则特征值tag=0,等于key的关键字应插在指针pt所指结点中第i和第i+1个关键字之间
int i=0;
int found=FALSE;
BTree p=T;
BTree q=NULL; //初始化,p指向待查结点,q指向p的双亲
while(p && !found)
{
i=Search(p,key); //在p->key[1...keynum]中查找i,使得:p->key[i]<=key<p->key[i+1]
if(i>0 && p->key[i]==k)
found=TRUE; //找到待查关键字
else
{
q=p;
p=p->ptr[i];
}
}
if(found)
return (p,i,1); //查找成功
else
return (q,i,0); //查找不成功,返回K的插入位置信息
}
三、B树的插入
B树的插入过程可描述为,利用B树的查找操作查找关键字k的插入位置。若找到,则说明该关键字已经存在,直接返回;否则查找操作必失败于某个最底层的非终端结点上,在该结点插入后,若其关键字总数n未达到m,算法结束,否则需分裂结点。
分裂的方法是,生成一新结点,从中间位置把结点(不包括中间位置的关键字)分成两部分。前半部分留在旧结点中,后半部分复制到新结点中,中间位置的关键字连同新结点的存储位置插入到父结点中。如果插入后父结点的关键字个数也超过m-1,则继续分裂。这个向上分裂过程如果持续到根结点,则会产生新的根结点。
结点分裂示例

B树的插入动图示例

三阶B树插入示例

void split(BTree& q, int s, BTree& ap)
{ //将q结点分裂成两个结点,前一半保留在原节点,后一半移入ap所指新结点
int i = 0;
int j = 0;
int n = q->keynum;
ap = (BTNode*)malloc(sizeof(BTNode)); //生成新结点
ap->ptr[0] = q->ptr[s];
for (i = s + 1, j = 1; j <= n; i++, j++)
{ //后一半移入ap结点
ap->key[j] = q->key[i];
ap->ptr[j] = q->ptr[i];
}
ap->keynum = n - s;
ap->parent = q->parent;
for (i = 0; i <= n - s; i++) //修改新结点的子节点的parent域
{
if (ap->ptr[i] != NULL)
{
ap->ptr[i]->parent = ap;
}
q->keynum = s - 1; //q结点的前一半保留,修改keynum
}
}
void newRoot(BTree& t, BTree p, int x, BTree ap)
{ //生成新的根节点
t = (BTNode*)malloc(sizeof(BTNode));
t->keynum = 1;
t->ptr[0] = p;
t->ptr[1] = ap;
t->key[1] = x;
if (p != NULL)
p->parent = t;
if (ap != NULL)
ap->parent = t;
t->parent = NULL; //新根的双亲是空指针
}
void Insert(BTree& q, int i, int x, BTree ap)
{ //关键字x和新结点指针ap分别插入到q->key[i]和q->ptr[i]
int j = 0;
int n = q->keynum;
for (j = n; j >= i; j--)
{
q->key[j + 1] = q->key[j];
q->ptr[j + 1] = q->ptr[j];
}
q->key[i] = x;
q->ptr[i] = ap;
if (ap != NULL)
ap->parent = q;
q->keynum++;
}
void InsertBTree(BTree& t, int k, BTree q, int i)
{ //在B树t中q结点的key[i-1]和key[i]之间插入关键字k
//若插入后结点关键字个数等于B树的阶,则沿双亲指针链进行结点分裂,使t仍是m阶B树
int x = 0;
int s = 0;
int finished = 0;
int needNewRoot = 0;
BTree ap;
if (!q)
newRoot(t, NULL, k, NULL); //生成新的根节点
else
{
x = k;
ap = NULL;
while (needNewRoot == 0 && finished == 0)
{
Insert(q, i, x, ap); //x和ap分别插入到q->key[i]和q->ptr[i]
if (q->keynum < m)
finished = 1; //插入完成
else
{ //分裂q结点
s = (m + 1) / 2;
split(q, s, ap);
x = q->key[s];
if (q->parent != NULL)
{
q = q->parent;
i = Search(q, x); //在双亲结点中查找x的插入位置
}
else
needNewRoot = 1;
}
}
if (needNewRoot == 1) //t是空树或者根结点已分裂为q和ap结点
newRoot(t, q, x, ap); //生成含信息(q,x,ap)的新的根节点t
}
}
四、B树的删除

二十一、B树的定义、查找、插入和删除的更多相关文章
- Java创建二叉搜索树,实现搜索,插入,删除操作
Java实现的二叉搜索树,并实现对该树的搜索,插入,删除操作(合并删除,复制删除) 首先我们要有一个编码的思路,大致如下: 1.查找:根据二叉搜索树的数据特点,我们可以根据节点的值得比较来实现查找,查 ...
- AVL树C++实现(插入,删除,查找,清空,遍历操作)
AVL.h文件代码 #pragma once #include<iostream> #include<stack> #include <assert.h> usin ...
- HDU_2871 线段树+vecor的中间插入和删除使用
本来这个题目就是个合并区间的题,就跟Hotel一样,要插入一段,则找左孩子 合并后的中间区间 右孩子,但是比较恶心的是,他需要实时得到某一段的起终点,或者某个点在第几个段里面,我想过在线段树里面加入几 ...
- 二叉搜索树(BST)的插入和删除递归实现
思路 二叉搜索树的插入 TreeNode InsertRec(rootNode, key) = if rootNode == NULL, return new Node(key) if key > ...
- 数据结构与算法16—平衡二叉(AVL)树
我们知道,对于一般的二叉搜索树(Binary Search Tree),其期望高度(即为一棵平衡树时)为log2n,其各操作的时间复杂度O(log2n)同时也由此而决定.但是,在某些极端的情况下(如在 ...
- 牢记!SQL Server数据库开发的二十一条注意点
如果你正在负责一个基于SQL Server的项目,或者你刚刚接触SQL Server,你都有可能要面临一些数据库性能的问题,这篇文章会为你提供一些有用的指导(其中大多数也可以用于其它的DBMS). ...
- SQL Server数据库开发的二十一条军规
如果你正在负责一个基于SQL Server的项目,或者你刚刚接触SQL Server,你都有可能要面临一些数据库性能的问题,这篇文章会为你提供一些有用的指导(其中大多数也可以用于其它的DBMS).在这 ...
- AVL 树的插入、删除、旋转归纳
参考链接: http://blog.csdn.net/gabriel1026/article/details/6311339 1126号注:先前有一个概念搞混了: 节点的深度 Depth 是指从根 ...
- 与TableView插入、删除、移动、多选,刷新控件
一.插入.删除.移动.多选 方法一: Cell的插入.删除.移动都有一个通用的方法,就是更新tableView的数据源,再reloadData,这样做实现上是简单一点,但是reloadData是刷新整 ...
随机推荐
- 微服务组件--注册中心Spring Cloud Eureka分析
Eureka核心功能点 [1]服务注册(register):Eureka Client会通过发送REST请求的方式向Eureka Server注册自己的服务,提供自身的元数据,比如ip地址.端口.运行 ...
- SpringBoot内置工具类,告别瞎写工具类了
不知大家有没有注意到,接手的项目中存在多个重复的工具类,发现其中很多功能,Spring 自带的都有.于是整理了本文,希望能够帮助到大家! 一.断言 断言是一个逻辑判断,用于检查不应该发生的情况 Ass ...
- OpenMP 入门
OpenMP 入门 简介 OpenMP 一个非常易用的共享内存的并行编程框架,它提供了一些非常简单易用的API,让编程人员从复杂的并发编程当中释放出来,专注于具体功能的实现.openmp 主要是通过编 ...
- 5 why 分析法,一种用于归纳抽象出解决方案的好方法
最近在看了<微信背后的产品观 - 张小龙手抄版>,其中有段话如下: 用户需求是零散的,解决方案是归纳抽象的过程 那如何归纳抽象呢?是否有一定的实践方法论呢?经过一轮探讨和学习,有这些答案: ...
- while循环条件不成立却无法跳出死循环的问题
在进入循环的时候,实际上是将A从内存加载到寄存器里面运行的,在整个循环中,A这个变量都只是在读取寄存器里面的值. 而当进入中断的时候,中断里面会从内存加载A到寄存器,修改完之后又存到内存里,然后退出中 ...
- Codeforces Round #791(Div 2)——D
D Problem - D - Codeforces 题意: 给定一个有向图,每个点有自己的点权,求一条长度为K的路径使得路径上的最大点权最小,输出该条路径上的最大点权. 思路:(二分+拓扑排序) 最 ...
- chrome工具调试
项目调试的困境 程序开发总会遇到各种各样的问题,为什么实际结果和预期结果不一致? 这个时候如果能深入程序内部抽丝剥茧去一探究竟再好不过! 而chrome工具是前端开发的杀手锏,经常听到的一句话是: 出 ...
- Oracle:ORA-39006、ORA-39213解决办法
执行Oracle数据库导入,遇到报错ORA-39006: internal error.ORA-39213: Metadata processing is not available.这还是第一次遇到 ...
- mybatis中association和collection使用
mybatis中association和collection使用 一.概述 association:一个复杂的类型关联.许多结果将包成这种类型 collection:复杂类型的集合 这2个属性的使用, ...
- .NET复习总纲
以下是自己学习遇到比较好的课程和学习网站,如果大家有更好的课程推荐,可以打在评论区或者私聊我,让我也进行学习和补充进文档 一..NET基础 官方文档:https://learn.microsoft.c ...