前几天由于出行计划没有更博QwQ
(其实是因为调试死活调不出来了TAT我好菜啊)
伸展树(英语:Splay Tree)是一种二叉查找树,它能在O(log n)内完成插入、查找和删除操作。它是由丹尼尔·斯立特(Daniel Sleator)和罗伯特·塔扬在1985年发明的[1]。
在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行调整,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。
它的优势在于不需要记录用于平衡树的冗余信息。
- 可靠的性能——它的平均效率不输于其他平衡树[2]。
- 存储所需的内存少——伸展树无需记录额外的什么值来维护树的信息,相对于其他平衡树,内存占用要小。
伸展树最显著的缺点是它有可能会变成一条链。这种情况可能发生在以非降顺序访问n个元素之后。然而均摊的最坏情况是对数级的——O(log n)
以上摘自中文Wikipedia
永远不要用单旋代替双旋...单旋那叫Spaly,Splay中的势能分析在单旋时会失效,复杂度不对的...(警告某整天单旋的ryf)
Rotate操作:
在离散数学中,树旋转(英语:Tree rotation)是在二叉树中的一种子树调整操作, 每一次旋转并不影响对该二叉树进行中序遍历的结果. 树旋转通常应用于需要调整树的局部平衡性的场合。
然后上几张图来作一下左旋/右旋的说明:
(第一张是动图不知道cnblogs能不能很好地滋磁GIF)
我们可以将左旋理解为将根旋转为右子节点的左子树,右旋为将根旋转为左子节点的右子树(往哪旋根就变成哪边的子树)
附C++袋马实现(左右合并,k=0为左旋,k=1为右旋)
#define lch chd[0] #define rch chd[1] #define kch chd[k] #define xch chd[k^1] void Rotate(Node* root,int k){ Node* tmp=root->xch; if(root->prt==NULL) this->root=tmp; else if(root->prt->lch==root) root->prt->lch=tmp; else root->prt->rch=tmp; tmp->prt=root->prt; root->xch=tmp->kch; if(root->xch!=NULL) root->xch->prt=root; tmp->kch=root; root->prt=tmp; }