📄 p356.cpp
字号:
#include "p353.cpp"
template <class Type> int Btree<Type>::Remove ( const Type & x ) {
//从驻留磁盘上的m阶B-树上删除x。
Triple<Type> loc = Search (x); //在树中搜索x
if ( loc.tag ) return 0; //x不在B-树中, 返主
Mnode<Type> *p = loc.r, *q, *s; //p是关键码x所在结点
int j = loc.i; //j是关键码在结点中的位置
if ( p->ptr[j] != NULL ) { //若p非叶结点
s = p->ptr[j]; GetNode (s); q = p; //读取磁盘上的s结点
while ( s != NULL ) { q = s; s = s->ptr[0]; } //找大于x但最接近于x的最小关键码(q是叶结点)
p->key[j] = q->key[1]; //用最小关键码填补
compress ( q, 1 ); //在q结点中关键码与指针前移填补key[1], q->n减1
p = q; //下一步处理q结点中的删除
}
else compress ( p, j ); //p是叶结点, 关键码与指针前移填补key[j], p->n减1
int d = (m+1)/2; //结点容纳关键码的下限
if (!(p==root))
while (1) {
if ( p->n < d-1 ) { //需要调整
j = 0; q = p->parent; //在q中找指向p的指针
GetNode (q);
while ( j <= q->n && q->ptr[j] != p ) j++;
if ( !j ) LeftAdjust ( p, q, d, j ); //p是q的最左子女, 与其右兄弟与双亲结点做调整
else
if (j==q->n) RightAdjust ( p, q, d, j ); //p是q的最右子女, 与其左兄弟与双亲结点做调整
else //p是中间,选择一个较简单的合并方法
if ( (q->ptr[j+1]->n) > d-1 ) LeftAdjust(p,q,d,j);
else
RightAdjust ( p, q, d, j );
p = q; //继续向上做结点调整工作
if ( p == root ) break;
}
else break; //不需要进行调整, 跳出循环
}
if ( !root->n ) { //当根结点为空时删根结点
p = root->ptr[0]; delete root; root = p;
if (root) root->parent = NULL;
}
return 1;
}
template <class Type>
void Btree<Type>::LeftAdjust ( Mnode<Type> *p, Mnode<Type> *q, const int d, const int j ) {
Mnode<Type> *p1 = q->ptr[j+1]; //p的右兄弟
if ( p1->n > d-1 ) { //右兄弟空间还够, 不用合并, 仅做调整
( p->n ) ++;
p->key[p->n] = q->key[j+1]; //双亲结点相应关键码下移
q->key[j+1] = p1->key[1]; //右兄弟最小关键码上移到双亲结点
p->ptr[p->n] = p1->ptr[0]; //右兄弟最左指针左移
compress ( p1, 0 );
}
else merge ( p, q, p1,j ); //p与p1合并, 保留p结点
}
template <class Type> void Btree<Type>::compress ( Mnode<Type> *p, const int j ) {
for ( int i=j; i<p->n; i++ ) //左移
{ p->key[i] = p->key[i+1]; p->ptr[i] = p->ptr[i+1]; }
p->n --; //结点中元素个数减1
}
template <class Type>
void Btree<Type>::merge ( Mnode<Type> *p, Mnode<Type> *q, Mnode<Type> *p1, const int j) {
p->key[(p->n)+1] = q->key[j+1]; //从双亲结点下降一个关键码
p->ptr[(p->n)+1] = p1->ptr[0]; //从右兄弟结点左移一个指针
for ( int k=1; k<=p1->n; k++ ) { //从右兄弟结点
p->key[(p->n)+k+1] = p1->key[k]; //关键码从p1到p左移
p->ptr[(p->n)+k+1] = p1->ptr[k]; //指针从p1到p左移
}
compress ( q, j+1 ); //双亲结点q中值与指针左移
p->n = p->n + p1->n + 1;
delete p1;
}
template <class Type>
void Btree<Type>::RightAdjust ( Mnode<Type> *p, Mnode<Type> *q, const int d, const int j )
//此程序与LeftAdjust功能基本相同,但与LeftAdjust是对称的:左右指针互换,前端与后端互换。
{
Mnode<Type> *p1 = q->ptr[j-1]; //p的左兄弟
if ( p1->n > d-1 ) { //左兄弟空间还够, 不用合并, 仅做调整
( p->n ) ++;
for (int i=p->n; i>=1;i--)
{
p->key[i]=p->key[i-1];
p->ptr[i]=p->ptr[i-1];
}
p->key[1]=q->key[j];
q->key[j]=p1->key[p1->n];
p->ptr[0]=p1->ptr[p1->n];
(p1->n)--;
}
else merge ( p1, q, p,j-1 ); //p1与p合并, 保留p结点
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -