标签:template 伸展树 osi class 保留 play arc else child
#ifndef Splay_hpp
#define Splay_hpp
#include "BST.hpp"
//伸展树
template <typename T> class Splay : public BST<T> {
protected:
BinNodePosi(T) splay(BinNodePosi(T) v); //将节点伸展至根
public:
BinNodePosi(T) & search(const T& e) override; //查找
BinNodePosi(T) insert(const T& e) override; //插入
bool remove(const T& e); //删除
};
//在节点*p与*lc(可能为空)之间建立父(左)子关系
template <typename NodePosi> inline
void attachAsLChild(NodePosi p,NodePosi lc) {
p -> lc = lc;
if (lc) {
lc -> parent = p;
}
}
//在节点*p与*rc(可能为空)之间建立父(右)子关系
template <typename NodePosi> inline
void attachAsRChild(NodePosi p,NodePosi rc) {
p -> rc = rc;
if (rc) {
rc -> parent = p;
}
}
//Splay树伸展算法:从节点v出发逐层伸展
template <typename T>
BinNodePosi(T) Splay<T>::splay(BinNodePosi(T) v) {
//v为因最近访问而需伸展的节点位置
if (!v) {
return NULL;
}
BinNodePosi(T) p;
BinNodePosi(T) g; //*v的父亲与祖父
//自下而上,反复对*v做双层伸展
while ( (p = v->parent) && (g = p->parent) ) {
BinNodePosi(T) gg = g -> parent; //每轮之后*v都以原曾祖父(great-grand parent)为父
if (IsLChild(*v)) {
if (IsLChild(*p)) { //zig--zig
attachAsLChild(g, p->rc);
attachAsLChild(p, v->rc);
attachAsRChild(p, g);
attachAsRChild(v, p);
}else{ //zig---zag
attachAsLChild(p, v->rc);
attachAsRChild(g, v->lc);
attachAsLChild(v, g);
attachAsRChild(v, p);
}
}else if (IsRChild(*p)) { //zag---zag
attachAsRChild(g, p->lc);
attachAsRChild(p, v->lc);
attachAsLChild(p, g);
attachAsLChild(v, p);
}else{ //zag---zig
attachAsRChild(p, v->lc);
attachAsLChild(g, v->rc);
attachAsRChild(v, g);
attachAsLChild(v, p);
}
if (!gg) {
//若*v原先的曾祖父*gg不存在,则*v现在应为树根
v -> parent = NULL;
}else{
//否则, *gg此后应该以*v作为左或右孩子
( g == gg->lc) ? attachAsLChild(gg, v) : attachAsRChild(gg, v);
}
this -> updateHeight(g);
this -> updateHeight(p);
this -> updateHeight(v);
}//双层伸展结束时,必有g == NULL,但p可能非空
if ( (p = v->height) ) {
//若p果真非空,则额外再做一次单旋
if (IsLChild(*v)) {
attachAsLChild(p, v->rc);
attachAsRChild(v, p);
}else{
attachAsRChild(p, v->lc);
attachAsLChild(v, p);
}
this -> updateHeight(p);
this -> updateHeight(v);
}
v -> parent = NULL;
return v;
}//调整之后新树根应为被伸展的节点,故返回该节点的位置以便上层函数更新树根
template <typename T> BinNodePosi(T) & Splay<T>::search(const T &e) {
BinNodePosi(T) p = searchIn(this->_root, e, this->_hot = NULL);
this->_root = splay(p ? p : this->_hot); //将最后一个被访问的节点伸展至根
return this->_root;
}//与其他BST不同,无论查找成功与否,_root都指向最后被访问的节点
//将关键码e插入伸展树中
template <typename T> BinNodePosi(T) Splay<T>::insert(const T &e) {
if (!this->_root) {
//处理原树为空的退化情况
this->_size++;
return this->_root = new BinNode<T>(e);
}
if (e == search(e) -> data) {
return this->_root; //确认目标节点不存在
}
this -> _size++;
BinNodePosi(T) t = this->_root;
if (this->_root->data < e) { //插入新根,以t和t->rc为左、右孩子
t -> parent = this->_root = new BinNode<T>(e, NULL, t, t->rc); //2+3个
if (HasRChild(*t)) {
t -> rc -> parent = this->_root;
t -> rc = NULL; // <= 2个
}
}else{
t -> parent = this->_root = new BinNode<T>(e, NULL, t->lc, t); //2+3个
if (HasLChild(*t)) {
t->lc->parent = this->_root;
t -> lc = NULL;
}
}
this -> updateHeightAbove(t); //更新t及其祖先(实际上只有_root一个)的高度
return this->_root; //新节点必然置于树根,返回之
}//无论e是否存在于原树中,返回时总有_root->data==e
template <typename T> bool Splay<T>::remove(const T &e) {
if (!this->_root || (e != search(e) ->data )){
//若树空或目标不存在,则无法删除
return false;
}
BinNodePosi(T) w = this->_root;
if (!HasLChild(*this->_root)) {
//若无左子树,则直接删除
this->_root = this->_root->rc;
if (this->_root) {
this->_root->parent = NULL;
}
}else if( !HasRChild(*this->_root) ){
//若无右子树,也直接删除
this -> _root = this->_root->lc;
if (this -> _root) {
this -> _root -> parent = NULL;
}
}else{
//若左右子树同时存在,则暂时将左子树切除,只保留右子树
BinNodePosi(T) lTree = this->_root->lc;
lTree -> parent = NULL;
this->_root->lc = NULL;
this->_root = this->_root->rc;
this->_root->parent = NULL;
//以原树根为目标,做一次(必定失败的)查找
search(w->data);
//至此,右子树中最小节点必伸展至根,且(因无雷同节点)其左子树必空,于是只需将原左子树接回原位即可
this->_root->lc = lTree;
lTree->parent = this->_root;
}
delete w->data;
delete w;
this->_size--;
if (this -> _root) {
//此后,若树非空,则树根的高度需要更新
this->updateHeight(this->_root);
}
return true;
}//若目标节点存在且被删除,返回true,否则返回false
#endif /* Splay_hpp */
标签:template 伸展树 osi class 保留 play arc else child
原文地址:https://www.cnblogs.com/gkp307/p/9621087.html