现在的位置: 首页 > 综合 > 正文

删除二叉排序树中的一个节点

2017年09月09日 ⁄ 综合 ⁄ 共 1326字 ⁄ 字号 评论关闭

http://blog.csdn.net/arcsinsin/article/details/10238505

假设被删结点是*p,其双亲是*f,不失一般性,设*p是*f的左孩子,下面分三种情况讨论:
⑴ 若结点*p是叶子结点,则只需修改其双亲结点*f的指针即可。
⑵ 若结点*p只有左子树PL或者只有右子树PR,则只要使PL或PR 成为其双亲结点的左子树即可。
⑶ 若结点*p的左、右子树均非空,先找到*p的中序前趋结点*s(注意*s是*p的左子树中的最右下的结点,它的右链域为空),然后有两种做法:
① 令*p的左子树直接链到*p的双亲结点*f的左链上,而*p的右子树链到*p的中序前趋结点*s的右链上。
② 以*p的中序前趋结点*s代替*p(即把*s的数据复制到*p中),将*s的左子树链到*s的双亲结点*q的左(或右)链上。(在下面的演示算法中用的就是此方法)

//删除二叉排序树中的一个节点
//在二叉排序树T中删除关键字为key的结点
void DelBST(BTree *T,int key){
 BTree *p=T,*f,*q,*s,*root=T;
 while(p){
  if(p->data==key) break; //找到关键字为key的结点
        f=p;//记下关键字key节点的父节点
  p=(key<p->data)?p->lchild:p->rchild;//分别在*p的左、右子树中查找
 }
 if(!p) return;//二叉排序树中无关键字为key的结点
 if(p->lchild==NULL&&p->rchild==NULL){//p没有左右子树
  if(p==T) T=NULL;//删除的是根节点
  else
   if(p==f->lchild)
    f->lchild=NULL;
   else
    f->rchild=NULL;
 free(p);
 }
 else if(p->lchild==NULL&&p->rchild!=NULL)//p无左子树有右子树
 { 
  if(f->lchild==p)
   f->lchild=p->rchild; //将p的右子树链接到其父结点的左链上
  else
   f->rchild=p->rchild; //将p的右子树链接到其父结点的右链上
  free(p);
 }
    else if(p->rchild==NULL&&p->lchild!=NULL)//p有左子树无右子树
 { 
  if (f->lchild==p)               
   f->lchild=p->lchild; //将p的左子树链接到其父结点的左链上
  else
   f->rchild=p->lchild; //将p的左子树链接到其父结点的右链上
  free(p);
 }
 else if(p->lchild!=NULL&&p->rchild!=NULL)//p既有左子树又有右子树
 {
  q=p;
  s=p->lchild;//转左
  while(s->rchild){//然后向右到尽头
   q=s;
   s=s->rchild;//s指向被删节点的“前驱”(中序前驱)
  }
  p->data=s->data;//以p的中序前趋结点s代替p(即把s的数据复制到p中)
  if(q!=p) q->rchild=s->lchild;//重接q的右子树
  else q->lchild=s->lchild;//重接q的左子树。
  free(s);
    }
}
【上篇】
【下篇】

抱歉!评论已关闭.