C++实现高级二叉搜索树——伸展树(Spaly)

参考:邓俊辉老师《数据结构C++语言实现》

根据局部性,当前访问的元素或者其邻近元素很大概率在不久的将来继续被访问,伸展树将被访问元素伸展至树根。

与AVL不同,zigzig结构或zagzag结构,Spaly每次都做双层伸展

              g                                                    v

        p                               ----->                        p

 v                                                                             g              (镜像同理)

而zigzag或zagzig结构则与AVL的旋转方式相同

优点:

1、无需记录节点高度、平衡因子,分摊复杂度有O(logn)与AVL相当

2、局部性强,缓存命中率高,复杂度可以到O(logk),k为可能访问到的数据量;任何连续的m次查找,都可以在O(mlogk+nlogn)时间内完成

缺陷:

1、结构可能极不平衡

2、不适用于单次操作效率要求敏感的场合(手术室控制)

3、复杂度分析复杂

代码:

定义:

//
// Created by Jayson on 2023/8/4.
//
#include "BST.h"
#include <iostream>
using namespace std;

template<typename T>
class Splay :public BST<T>{
public:
    BinNode<T>*& search(T e);
    BinNode<T>* insert(T e);
    bool remove(T e);

    BinNode<T>* splay(BinNode<T>*v);
};

实现:

//辅助函数
template<typename T>
void attachAsLchild(BinNode<T>*p, BinNode<T>*lc){
    p->lchild = lc;
    if(lc) lc->parent = p;
}
template<typename T>
void attachAsRchild(BinNode<T>*p, BinNode<T>*rc){
    p->rchild = rc;
    if(rc) rc->parent = p;
}
template<typename T>
BinNode<T>* Splay<T>::splay(BinNode<T> *v) {
    if(!v) return NULL;
    BinNode<T>* p ;
    BinNode<T>* g ;

    while((p=v->parent) && (g=p->parent)){
        BinNode<T>* gg = g->parent;
        int temp;
        if(gg && g==gg->lchild)temp =1;
        else if(gg && g ==gg->rchild)temp =2;
        if(p == g->lchild){
            if(v == p->lchild){
                attachAsLchild(g,p->rchild);
                attachAsRchild(g,g->rchild);
                attachAsLchild(p,v->rchild);
                attachAsRchild(p,g);
                attachAsLchild(v,v->lchild);
                attachAsRchild(v,p);
            }else{
                attachAsLchild(p,p->lchild);
                attachAsRchild(p,v->lchild);
                attachAsLchild(g,v->rchild);
                attachAsRchild(g,g->rchild);
                attachAsLchild(v,p);
                attachAsRchild(v,g);
            }
        }else{
            if(v == p->rchild){
                attachAsLchild(g,g->lchild);
                attachAsRchild(g,p->lchild);
                attachAsLchild(p,g);
                attachAsRchild(p,v->lchild);
                attachAsLchild(v,p);
                attachAsRchild(v,v->rchild);
            }else{
                attachAsLchild(g,g->lchild);
                attachAsRchild(g,v->lchild);
                attachAsLchild(p,v->rchild);
                attachAsRchild(p,p->rchild);
                attachAsLchild(v,g);
                attachAsRchild(v,p);
            }

        }
        if(!gg){
            v->parent = NULL;
        }else{
            v->parent = gg;
            if(temp == 1)gg->lchild = v;
            else gg->rchild = v;
        }
        this->updateHeight(g);
        this->updateHeight(p);
        this->updateHeight(v);
    }
    p = v->parent;
    if(p){//由于是双层伸展,若总层数为单层,最后需要再来一次单层旋转
        if(v == p->lchild){
            attachAsLchild(p,v->rchild);
            attachAsRchild(v,p);
        }else{
            attachAsRchild(p,v->lchild);
            attachAsLchild(v,p);
        }
        this->updateHeight(p);
        this->updateHeight(v);
    }
    v->parent = NULL;
    return v;//v伸展到树根
}

template<typename T>
BinNode<T>*& Splay<T>::search(T e) {
    BinNode<T>* x = searchIN(this->_root,e,this->_hot = NULL);
    if(x){
        this->_root = splay(x);
    }else{
        this->_root = splay(this->_hot);
    }
    return this->_root;
}

template<typename T>
BinNode<T>* Splay<T>::insert(T e) {
    if(!this->_root){
        this->_size = 1;
        this->_root = new BinNode<T>(e);
        return this->_root;
    }
    //若存在插入的值,则伸展它,并返回根
    search(e);
    if(this->_root->value == e)return this->_root;
    //不存在,则插入
    this->_size++;
    BinNode<T>* t = this->_root;
    if(t->value < e){
        this->_root = new BinNode<T>(e,NULL,t,t->rchild);
        t->parent = this->_root;
        if(t->rchild){
            t->rchild->parent = this->_root;
            t->rchild = NULL;
        }
    }else{
        this->_root = new BinNode<T>(e,NULL,t->lchild,t);
        t->parent = this->_root;
        if(t->lchild){
            t->lchild->parent = this->_root;
            t->lchild = NULL;
        }
    }
    this->updateHeightAbove(t);
    return this->_root;
}

template<typename T>
bool Splay<T>::remove(T e) {
    if(!this->_root)return false;
    search(e);
    if(this->_root->value != e)return false;

    if(!this->_root->lchild){
        this->_root = this->_root->rchild;
        if(this->_root)this->_root->parent = NULL;
    }else if(!this->_root->rchild){
        this->_root = this->_root->lchild;
        if(this->_root)this->_root->parent = NULL;
    }else{
        BinNode<T>* lTree = this->_root->lchild;
        lTree->parent = NULL; this->_root->lchild = NULL;
        this->_root = this->_root->rchild;
        this->_root->parent = NULL;
        search(e);
        this->_root->lchild = lTree;
        lTree->parent = this->_root;
    }

    this->_size--;
    if(this->_root)this->updateHeight(this->_root);
    return true;
}

测试:

#include "BST.h"
#include "BST.cpp"
#include "BinTree.h"
#include "BinTree.cpp"
#include "AVL.h"
#include "Spaly.h"
#include <iostream>
using namespace std;

int main(){
    Splay<int>* sp = new Splay<int>();

    sp->insert(1);
    sp->insert(2);
    sp->insert(3);
    sp->insert(4);
    sp->insert(5);
    cout<<sp->root()->value<<endl;
    sp->search(1);
    cout<<sp->root()->value;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值