由于在BST模板类,插入与删除算法都是virtual,需要重写。
template<typename T>BinNodePosi(T) BST<T>::insert(const T& e){
BinNodePosi(T) &x = Search(e);
if(x) return x;
else{
x = new BinNode<T>(e,_hot);
_size++;
updateHeightAbove(x);
return x;
}
}
而删除算法就有问题了。不能向插入算法直接找到位置插入进去就OK,分成两种情况。
单分支情况,只有一个孩子的情况下。比方说v->lc=x,v->rc=NULL.只需令v->parent->lc=NULL即可。只含有右子树的
情况完全雷同。
双分支情况,左右孩子都在的情况下,就不能采用此策略,必须找到v->succ(),swap(v->data,v->succ->data),转而删除v->succ就可以
template<typename T>bool BST<T>::remove(const T& e){
BinNodePosi(T) &x = Search(e);
if(!x) return false;
else{
_size--;
removeAt(x,_hot);
updateHeightAbove(x->parent);//即命中节点的父亲_hot;
return true;
}
}
主算法的思路简洁明了。removeAt(BinNodePosi(T) &x,BinNodePosi(T) &hot)则实现了我们上述的思想。
template<typename T>static removeAt(BinNodePosi(T) &x,BinNodePosi(T) &_hot){
BinNodePosi(T) w = x;
BinNodePosi(T) succ = NULL;
//单分支情况
if(!HasLChild(x))
succ = x->rc; x=x->rc;
else if(!HasRChild)
succ = x->lc; x=x->lc;
else{
//双分支的情况
w = w->succ();
swap(x->data,w->data);
BinNodePosi(T) u = w->parent;
((u==w)?u->rc:r->lc) = succ = w->rc;
}
//记录实际被删除节点的父亲
hot = w->parent;
//将被删除节点与hot关联。
if(succ) succ->parent = hot;
release(w->data);
release(w);
return succ
}
}
考察插入算法与删除算法的复杂度。
插入算法:
复杂度来源主要有2个,一个是search()接口和updateHeightAbove()接口。最坏的程度也就全树的高度。删除算法:
复杂度来源主要有3个,search()接口和updateHeightAbove()接口和succ()接口,同理这三个接口做和在大O记号下也不过全树的高度。
但是,删除算法有个致命的缺点。若执行removeAt()操作,总是固定地将删除的二度节点与其直接后继交换,随着操作次数的增加,二叉搜索树向左倾斜的趋势愈加明显。
所以,平衡树高才是解决以上算法最核心的解决方案。