参考:邓俊辉老师《数据结构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;
}