1 删除操作过程分析
从BST树上删除一个结点,仍然要保证删除后满足BST的性质。设被删除结点为p,其父结点为f ,删除情况如下:
① 若p是叶子结点: 直接删除p。
② 若p只有一棵子树(左子树或右子树):直接用p的左子树(或右子树)取代p的位置而成为f的一棵子树。即原来p是f的左子树,则p的子树成为f的左子树;原来p是f的右子树,则p的子树成为f的右子树。
③ 若p既有左子树又有右子树 :处理方法有以下两种,可以任选其中一种。
◆ 用p的直接前驱结点代替p。即从p的左子树中选择值最大的结点s放在p的位置(用结点s的内容替换结点p内容),然后删除结点s。s是p的左子树中的最右边的结点且没有右子树,对s的删除同②。
◆ 用p的直接后继结点代替p。即从p的右子树中选择值最小的结点s放在p的位置(用结点s的内容替换结点p内容),然后删除结点s。s是p的右子树中的最左边的结点且没有左子树,对s的删除同②。
2 算法实现
void Delete_BST (BSTNode *T , KeyType key )
/* 在以T为根结点的BST树中删除关键字为key的结点 */
{
BSTNode *p=T , *f=NULL , *q , *s ;
while ( p!=NULL&&!EQ(p->key, key) )
{
f=p ;
if (LT(key, p->key) ) p=p->Lchild ; /* 搜索左子树 */
else p=p->Rchild ; /* 搜索右子树 */
}
if (p==NULL) return ; /* 没有要删除的结点 */
s=p ; /* 找到了要删除的结点为p */
if (p->Lchild!=NULL&& p->Rchild!=NULL)
{
f=p ;
s=p->Lchild ; /* 从左子树开始找 */
while (s->Rchild!=NULL)
{
f=s ;
s=s->Rchild ;
}
/* 左、右子树都不空,找左子树中最右边的结点 */
p->key=s->key ;
p->otherinfo=s->otherinfo ;
/* 用结点s的内容替换结点p内容 */
} /* 将第3种情况转换为第2种情况*/
if (s->Lchild!=NULL) /* 若s有左子树,右子树为空 */
q=s->Lchild ;
else q=s->Rchild ;
if (f==NULL) T=q ;
else if (f->Lchild==s) f->Lchild=q ;
else f->Rchild=q ;
free(s) ;
}