B树
时间复杂度: O(logn)
B树基本特征:
目录
一、创建
二、查找
三、分裂
四、插入
五、删除
六、完整代码
一、创建
思路
B树的创建,包含关键码个数,父亲结点,孩子指针数组并且第一个元素为空,关键码数组,这两个数组索引位置很巧妙,在下面的查找操作中十分合适,下图为这两个数组的抽象显示
代码实现
#define MAXM 10 //定义B树最大阶数
const int m = 4;//设定B树的阶数
const int Max = m - 1;//设定B树的最大关键码数
const int Min = (m - 1) / 2;//设定B数的最小关键码数等于(阶数-1)向下取整
typedef int KeyType;
typedef struct node
{
int keynum; //关键码个数
KeyType key[MAXM]; //关键码数组,key[0]不使用
struct node* parent; //双亲结点指针
struct node* ptr[MAXM]; //孩子结点指针数组
}BTNode, *BTree;
typedef struct //B树查找结果类型
{
BTree pt; //查找到的超级结点
int i; //所查元素在超级结点数组中的索引
int flag; //查找是否成功的标志
}Result;
typedef struct LNode //链表和链表结点类型
{
BTree data; //数据域
struct LNode* next; //指针域
}LNode, *LinkList;
typedef enum status
{
TRUE,
FALSE,
OK,
ERROR,
SOLVEOVERFLOW,
EMPTY
}Status;
返回目录
二、查找
思路
当查询一个关键码时,如果查到,就返回那个结点和所在索引位置;如果没有查到,就返回应该插入的位置
代码实现
int SearchBTNode(BTNode* p, KeyType k)
{
int i = 0;
for (i = 0; i < p->keynum && p->key[i + 1] <= k; i++) {}
return i;
}
Result SearchBTree(BTree t, KeyType k)
{
Result r;
BTNode* p = t; //初始化结点p和q,p指向待查结点,q指向p的父亲
BTNode* q = nullptr;
int i = 0;
int found_flag = 0;
while (p && 0 == found_flag)
{
i = SearchBTNode(p, k);
if (i > 0 && p->key[i] == k)
{
found_flag = 1;
}
else
{
q = p;
p = p->ptr[i];
}
}
if (1 == found_flag)
{
r.pt = p;
r.i = i;
r.flag = 1;
}
else
{
r.pt = q;
r.i = i;
r.flag = 0;
}
return r; //返回查找元素的位置或者插入元素的位置
}
返回目录
三、分裂
思路
此处分裂原则是,
s = (m + 1) / 2
,将s作为新的父结点,s的左边为它的左孩子,右边为它的右孩子新分裂出的左孩子
⌊(m + 1) / 2⌋ - 1 = ⌈m / 2⌉ - 1
新分裂出的右孩子
m - ⌈m / 2⌉ = ⌊m / 2⌋
可见左右孩子都符合m阶B树的条件
代码实现
void SplitBTNode(BTNode*& p, BTNode*& q)
{
int s = (m + 1) / 2;
q = (BTNode*)malloc(sizeof(BTNode));
q->ptr[0] = p->ptr[s];
for (int i = s + 1; i <= m; i++)
{
q->key[i - s] = p->key[i];
q->ptr[i - s] = p->ptr[i];
}
q->parent = p->parent;
q->keynum = p->keynum - s;
for (int i = 0; i <= q->keynum; i++)
{
if (q->ptr[i])
{
q->ptr[i]->parent = q;
}
}
p->keynum = s - 1;
}
void NewRoot(BTNode*& t, KeyType k, BTNode* p, BTNode* q)
{
t = (BTNode*)malloc(sizeof(BTNode));
t->keynum = 1;
t->key[1] = k;
t->ptr[0] = p;
t->ptr[1] = q;
t->parent = nullptr;
if (p)
{
p->parent = t;
}
if (q)
{
q->parent = t;
}
t->parent=NULL;
}
返回目录
四、插入
思路
插入共有三种情况:
当前树为空,就新生成一个新的树,左右孩子为空
关键码插入后,超级结点没有超过最大关键码数
关键码插入后,超级结点超过了最大关键码数,首先分裂,将中间结点插入到它们的父亲结点,此时父亲结点没有超过最大关键码数
关键码插入后,超级结点超过了最大关键码数,首先分裂,将中间结点插入到它们的父亲结点,此时父亲结点超过了最大关键码数,将父亲结点再进行分裂,可能一直分裂到根结点,当根结点分裂完毕后,就停止分裂,新生成一个树,将它的左右孩子赋值为分裂后的两颗子树
代码实现
void InsertBTree(BTree& t, int i, KeyType k, BTNode* p)
{
BTNode* q = nullptr;
int newroot_flag, finished_flag, s;
KeyType x;
if (!p) //树t为空
{
NewRoot(t, k, nullptr, nullptr);
}
else
{
newroot_flag = 0;
finished_flag = 0;
x = k;
while (!newroot_flag && !finished_flag)
{
InsertBTNode(p, i, x, q);
if (p->keynum <= Max)
{
finished_flag = 1;
}
else
{
SplitBTNode(p, q);
s = (m + 1) / 2;
x = p->key[s];
if (p->parent)
{
p = p->parent;
i = SearchBTNode(p, x);
}
else
{
newroot_flag = 1;
}
}
}
if (1 == newroot_flag)
{
NewRoot(t, x, p, q);
}
}
}
返回目录
五、删除
思路
删除可以分为两种情况:
- 当左右兄弟可以借出结点时
- 当左右兄弟借不出结点时,就合并结点
代码实现
void Remove(BTNode* p, int i)
{
for (int j = i + 1; j <= p->keynum; j++)
{
p->key[j - 1] = p->key[j];
p->ptr[j - 1] = p->ptr[j];
}
p->keynum--;
}
void MoveRight(BTNode* p, int i)
{
BTNode* q = p->ptr[i];
BTNode* aq = p->ptr[i - 1];
for (int j = q->keynum; j > 0; j++)
{
q->key[j + 1] = q->key[j];
q->ptr[j + 1] = q->ptr[j];
}
q->ptr[1] = q->ptr[0];
q->key[1] = p->key[i];
q->keynum++;
p->key[i] = aq->key[aq->keynum];
p->ptr[i]->ptr[0] = aq->ptr[aq->keynum];
aq->keynum--;
}
void MoveLeft(BTNode* p, int i)
{
BTNode* q = p->ptr[i];
BTNode* aq = p->ptr[i - 1];
aq->key[aq->keynum + 1] = p->key[i];
aq->ptr[aq->keynum + 1] = q->ptr[0];
aq->keynum++;
p->key[i] = q->key[1];
q->ptr[0] = q->ptr[1];
for (int i = 2; i <= q->keynum; i++)
{
q->key[i - 1] = q->key[i];
q->ptr[i - 1] = q->ptr[i];
}
q->keynum--;
}
void Combine(BTNode* p, int i)
{
BTNode* q = p->ptr[i];
BTNode* aq = p->ptr[i - 1];
aq->keynum++;
q->key[q->keynum] = p->key[i];
q->ptr[q->keynum] = q->ptr[0];
for (int j = 1; j <= q->keynum; j++)
{
aq->keynum++;
aq->key[aq->keynum] = q->key[j];
aq->ptr[aq->keynum] = q->ptr[j];
}
for (int j = i; j < p->keynum; j++)
{
p->key[j] = p->key[j + 1];
p->ptr[j] = p->ptr[j + 1];
}
p->keynum--;
free(q);
}
void AdjustBTree(BTNode* p, int i)
{
if (0 == i)
{
if (p->ptr[1]->keynum > Min)
{
MoveLeft(p, 1);
}
else
{
Combine(p, 1);
}
}
else if (p->keynum == i)
{
if (p->ptr[i - 1]->keynum > Min)
{
MoveRight(p, i);
}
else
{
Combine(p, i);
}
}
else if (p->ptr[i - 1]->keynum > Min)
{
MoveRight(p, i);
}
else if (p->ptr[i + 1]->keynum > Min)
{
MoveLeft(p, i + 1);
}
else
{
Combine(p, i);
}
}
int FindBTNode(BTNode* p, KeyType k, int& i)
{
if (k < p->key[1])
{
i = 0;
return 0;
}
else
{
i = p->keynum;
while (k < p->key[i] && i > 1)
{
i--;
}
if (p->key[i] == k)
{
return 1;
}
else
{
return 0;
}
}
}
void Substitution(BTNode* p, int i)
{
BTNode* q;
for (q = p->ptr[i]; q->ptr[0] != nullptr; q = q->ptr[0])
{
p->key[i] = q->key[1];
}
}
int BTNodeDelete(BTNode* p, KeyType k)
{
int i;
int found_flag;
if (!p)
{
return 0;
}
else
{
found_flag = FindBTNode(p, k, i);
if (1 == found_flag)
{
if (p->ptr[i - 1] != nullptr)
{
}
else
{
Remove(p, i);
}
}
else
{
found_flag = BTNodeDelete(p->ptr[i], k);
}
if (p->ptr[i] != nullptr)
{
if (p->ptr[i]->keynum < Min)
{
AdjustBTree(p, i);
}
}
return found_flag;
}
}
void BTreeDelete(BTree& t, KeyType k)
{
BTNode* p;
int a = BTNodeDelete(t, k);
if (a == 0)
{
cout << "关键码k不在树中!" << endl;
}
else if (t->keynum)
{
p = t;
t = t->ptr[0];
free(p);
}
}
void DestroyBTree(BTree& t)
{
BTNode* p = t;
if (p)
{
for (int i = 0; i <= p->keynum; i++)
{
DestroyBTree(p->ptr[i]);
}
free(p);
}
t = nullptr;
}
返回目录
六、完整代码
#include <iostream>
#include <cstdlib>
using namespace std;
#define MAXM 10 //定义B树最大阶数
const int m = 4;//设定B树的阶数
const int Max = m - 1;//设定B树的最大关键码数
const int Min = (m - 1) / 2;//设定B数的最小关键码数等于(阶数-1)向下取整
typedef int KeyType;
typedef struct node
{
int keynum; //关键码个数
KeyType key[MAXM]; //关键码数组,key[0]不使用
struct node* parent; //双亲结点指针
struct node* ptr[MAXM]; //孩子结点指针数组
}BTNode, *BTree;
typedef struct //B树查找结果类型
{
BTree pt; //查找到的超级结点
int i; //所查元素在超级结点数组中的索引
int flag; //查找是否成功的标志
}Result;
typedef struct LNode //链表和链表结点类型
{
BTree data; //数据域
struct LNode* next; //指针域
}LNode, *LinkList;
typedef enum status
{
TRUE,
FALSE,
OK,
ERROR,
SOLVEOVERFLOW,
EMPTY
}Status;
Status InitBTree(BTree& t); //初始化B树
int SearchBTNode(BTNode* p, KeyType k); //在超级结点p中查找关键码k的插入位置i
Result SearchBTree(BTree t, KeyType k); //在树T上查找关键字k,返回结果(pt,i,tag)
//如果查找成功,tag = 1,关键码k是指针pt所指
//结点中的第i个关键字,否则特征值为tag = 0;
//将关键码K和结点q分别插入到p->key[i + 1]和p->ptr[i + 1]中
void InsertBTNode(BTNode*& p, int i, KeyType k, BTNode* q);
//将结点p分裂成两个结点,前一半保留,后一半移入结点q
void SplitBTNode(BTNode*& p, BTNode*& q);
//生成新的根结点t,原p和q为子树指针
void NewRoot(BTNode*& t, KeyType k, BTNode* p, BTNode* q);
/*在树t上结点q的key[i]与key[i+1]之间插入关键字k。若引起
结点过大,则沿双亲链进行必要的结点分裂调整,使t仍是B树*/
void InsertBTree(BTree& t, int i, KeyType k, BTNode* p);
//从p结点删除key[i]和它的孩子指针ptr[i]
void Remove(BTNode* p, int i);
//双亲结点p中的最后一个关键字移入右节点q中,将左结点aq中的最后一个关键字移入双亲结点p中
void MoveRight(BTNode* p, int i);
//双亲结点p中的第一个关键字移入结点aq中,将q中第一个关键字移入双亲结点p中
void MoveLeft(BTNode* p, int i);
//双亲结点p、右节点q合并入左结点aq,并调整双亲结点p中剩余关键字的位置
void Combine(BTNode* p, int i);
//删除结点p中的第i个关键字后,调整B树
void AdjustBTree(BTNode* p, int i);
//反应是否在结点p中找到关键字k
int FindBTNode(BTNode* p, KeyType k, int &i);
//查找被删关键字p->key[i](在非叶子结点中)的替代叶子结点(右子树中值最小的关键字)
void Substitution(BTNode* p, int i);
//在结点p中查找并删除关键字k
int BTNodeDelete(BTNode* p, KeyType k);
//构建删除框架,执行删除操作
void BTreeDelete(BTree& t, KeyType k);
//递归释放B树
void DestroyBTree(BTree& t);
Status InitBTree(BTree& t)
{
t = nullptr;
return OK;
}
int SearchBTNode(BTNode* p, KeyType k)
{
int i = 0;
for (i = 0; i < p->keynum && p->key[i + 1] <= k; i++) {}
return i;
}
Result SearchBTree(BTree t, KeyType k)
{
Result r;
BTNode* p = t; //初始化结点p和q,p指向待查结点,q指向p的父亲
BTNode* q = nullptr;
int i = 0;
int found_flag = 0;
while (p && 0 == found_flag)
{
i = SearchBTNode(p, k);
if (i > 0 && p->key[i] == k)
{
found_flag = 1;
}
else
{
q = p;
p = p->ptr[i];
}
}
if (1 == found_flag)
{
r.pt = p;
r.i = i;
r.flag = 1;
}
else
{
r.pt = q;
r.i = i;
r.flag = 0;
}
return r; //返回查找元素的位置或者插入元素的位置
}
void InsertBTNode(BTNode*& p, int i, KeyType k, BTNode* q)
{
for (int j = p->keynum; j > i; j--)
{
p->key[j + 1] = p->key[j];
p->ptr[j + 1] = p->ptr[j];
}
p->key[i + 1] = k;
p->ptr[i + 1] = q;
if (q)
{
q->parent = p;
}
p->keynum++;
}
void SplitBTNode(BTNode*& p, BTNode*& q)
{
int s = (m + 1) / 2;
q = (BTNode*)malloc(sizeof(BTNode));
q->ptr[0] = p->ptr[s];
for (int i = s + 1; i <= m; i++)
{
q->key[i - s] = p->key[i];
q->ptr[i - s] = p->ptr[i];
}
q->parent = p->parent;
q->keynum = p->keynum - s;
for (int i = 0; i <= q->keynum; i++)
{
if (q->ptr[i])
{
q->ptr[i]->parent = q;
}
}
p->keynum = s - 1;
}
void NewRoot(BTNode*& t, KeyType k, BTNode* p, BTNode* q)
{
t = (BTNode*)malloc(sizeof(BTNode));
t->keynum = 1;
t->key[1] = k;
t->ptr[0] = p;
t->ptr[1] = q;
t->parent = nullptr;
if (p)
{
p->parent = t;
}
if (q)
{
q->parent = t;
}
t->parent = NULL;
}
void InsertBTree(BTree& t, int i, KeyType k, BTNode* p)
{
BTNode* q = nullptr;
int newroot_flag, finished_flag, s;
KeyType x;
if (!p) //树t为空
{
NewRoot(t, k, nullptr, nullptr);
}
else
{
newroot_flag = 0;
finished_flag = 0;
x = k;
while (!newroot_flag && !finished_flag)
{
InsertBTNode(p, i, x, q);
if (p->keynum <= Max)
{
finished_flag = 1;
}
else
{
SplitBTNode(p, q);
s = (m + 1) / 2;
x = p->key[s];
if (p->parent)
{
p = p->parent;
i = SearchBTNode(p, x);
}
else
{
newroot_flag = 1;
}
}
}
if (1 == newroot_flag)
{
NewRoot(t, x, p, q);
}
}
}
void Remove(BTNode* p, int i)
{
for (int j = i + 1; j <= p->keynum; j++)
{
p->key[j - 1] = p->key[j];
p->ptr[j - 1] = p->ptr[j];
}
p->keynum--;
}
void MoveRight(BTNode* p, int i)
{
BTNode* q = p->ptr[i];
BTNode* aq = p->ptr[i - 1];
for (int j = q->keynum; j > 0; j++)
{
q->key[j + 1] = q->key[j];
q->ptr[j + 1] = q->ptr[j];
}
q->ptr[1] = q->ptr[0];
q->key[1] = p->key[i];
q->keynum++;
p->key[i] = aq->key[aq->keynum];
p->ptr[i]->ptr[0] = aq->ptr[aq->keynum];
aq->keynum--;
}
void MoveLeft(BTNode* p, int i)
{
BTNode* q = p->ptr[i];
BTNode* aq = p->ptr[i - 1];
aq->key[aq->keynum + 1] = p->key[i];
aq->ptr[aq->keynum + 1] = q->ptr[0];
aq->keynum++;
p->key[i] = q->key[1];
q->ptr[0] = q->ptr[1];
for (int i = 2; i <= q->keynum; i++)
{
q->key[i - 1] = q->key[i];
q->ptr[i - 1] = q->ptr[i];
}
q->keynum--;
}
void Combine(BTNode* p, int i)
{
BTNode* q = p->ptr[i];
BTNode* aq = p->ptr[i - 1];
aq->keynum++;
q->key[q->keynum] = p->key[i];
q->ptr[q->keynum] = q->ptr[0];
for (int j = 1; j <= q->keynum; j++)
{
aq->keynum++;
aq->key[aq->keynum] = q->key[j];
aq->ptr[aq->keynum] = q->ptr[j];
}
for (int j = i; j < p->keynum; j++)
{
p->key[j] = p->key[j + 1];
p->ptr[j] = p->ptr[j + 1];
}
p->keynum--;
free(q);
}
void AdjustBTree(BTNode* p, int i)
{
if (0 == i)
{
if (p->ptr[1]->keynum > Min)
{
MoveLeft(p, 1);
}
else
{
Combine(p, 1);
}
}
else if (p->keynum == i)
{
if (p->ptr[i - 1]->keynum > Min)
{
MoveRight(p, i);
}
else
{
Combine(p, i);
}
}
else if (p->ptr[i - 1]->keynum > Min)
{
MoveRight(p, i);
}
else if (p->ptr[i + 1]->keynum > Min)
{
MoveLeft(p, i + 1);
}
else
{
Combine(p, i);
}
}
int FindBTNode(BTNode* p, KeyType k, int& i)
{
if (k < p->key[1])
{
i = 0;
return 0;
}
else
{
i = p->keynum;
while (k < p->key[i] && i > 1)
{
i--;
}
if (p->key[i] == k)
{
return 1;
}
else
{
return 0;
}
}
}
void Substitution(BTNode* p, int i)
{
BTNode* q;
for (q = p->ptr[i]; q->ptr[0] != nullptr; q = q->ptr[0])
{
p->key[i] = q->key[1];
}
}
int BTNodeDelete(BTNode* p, KeyType k)
{
int i;
int found_flag;
if (!p)
{
return 0;
}
else
{
found_flag = FindBTNode(p, k, i);
if (1 == found_flag)
{
if (p->ptr[i - 1] != nullptr)
{
}
else
{
Remove(p, i);
}
}
else
{
found_flag = BTNodeDelete(p->ptr[i], k);
}
if (p->ptr[i] != nullptr)
{
if (p->ptr[i]->keynum < Min)
{
AdjustBTree(p, i);
}
}
return found_flag;
}
}
void BTreeDelete(BTree& t, KeyType k)
{
BTNode* p;
int a = BTNodeDelete(t, k);
if (a == 0)
{
cout << "关键码k不在树中!" << endl;
}
else if (t->keynum)
{
p = t;
t = t->ptr[0];
free(p);
}
}
void DestroyBTree(BTree& t)
{
BTNode* p = t;
if (p)
{
for (int i = 0; i <= p->keynum; i++)
{
DestroyBTree(p->ptr[i]);
}
free(p);
}
t = nullptr;
}