Splay tree 伸展树
1.基本思想:把本次访问的结点通过一系列的旋转操作,变换为根结点,同时要保持树为二叉查找树(BST)。
2.旋转操作:Zig,Zag.(代码注释中有说明)
3.核心操作:Splay(伸展).
4.5个基本操作:
Find(x,&Spt); //查找操作,在Spt中查找值为x的元素,然后把x所在的结点变为Splay tree的根结点
Insert(x,&Spt);//在spt中插入值为x的结点,并把x所在的结点变为Splay tree的根结点
Delete(x,&Spt);//在spt中删除值为x的结点
Join(&s1,&s2);//合并s1,s2两棵Splay tree
Split(x,&s,&s1,&s2);//把值为 x的 结点左右子树分离成2个Splay tree(s1,s2)
5.实现:(参考LRJ的书)
5(1).需要用到的数据结构:
int right[].left[],next[],father[];
DataType data[];
5(2).说明:
right[p],left[p]记录的是结点p的右儿子和左儿子.
father[p]是p 的父亲结点.
next[] 是存放结点的表,手动实现内存分配.
data[p]对应p结点存放的数据.
5(3).实现代码:
#include<iostream>
#include<queue>
using namespace std;
/**
** author: yfr
** date: 2012-1-10
** project: splay tree
** reference: LRJ's Book
**/
#define SIZE 100
int Left[SIZE],Right[SIZE],father[SIZE],next[SIZE],data[SIZE];
/**
基本函数声明
**/
void Init();
int newnode(int d);
void delnode(int p);
//********************************
void Zig(int &);
void Zag(int &);
void Splay(int &x,int &s);
int BST_find(int x,int p);
int SPT_find(int x,int &p);
int BST_insert(int x,int &p);
void SPT_insert(int x,int &p);
void remove(int x,int &p);
//********************************
int findmax(int &s);
int findmin(int &s);
int join(int &s1,int &s2);
void split(int x,int &s,int &s1,int &s2);
//********************************
/**
/ \
p x
/ \ Zig(x) / \
x <> -----------------> <> p
/ \ / \
<> <> <> <>
**/
//zig zag 函数 注意指针修改时要成对去修改
void Zig(int &x)
{
int p = father[x];
Left[p] = Right[x];
if(Right[x])//如果右子树存在
father[Right[x]] = p;
Right[x] = p;
father[x] = father[p];
father[p] = x;
//这步很关键!!
if(data[father[x]]>data[x])
Left[father[x]] = x;
else
Right[father[x]] = x;
}
/**
/ \
x p
/ \ Zag(x) / \
p <> <----------------- <> x
/ \ / \
<> <> <> <>
**/
void Zag(int &x)
{
int p = father[x];
Right[p] = Left[x];
if(Left[x])//如果左子树存在
father[Left[x]] = p;
Left[x] = p;
father[x] = father[p];
father[p] = x;
//这步很关键!!
if(data[father[x]]>data[x])
Left[father[x]] = x;
else
Right[father[x]] = x;
}
//s是树根,x是待伸长的结点
void Splay(int &x,int &s)
{
int p;
while(father[x])
{
p = father[x];
if(!father[p])//如果p是根
{
if( x == Left[p])
Zig(x);
else if( x == Right[p])
Zag(x);
}
else//如果不是树根
{
int g = father[p];//祖先结点
if(Left[g]==p && Left[p]==x) //LL的情况
{
Zig(p);
Zig(x);
}
else if(Left[g]==p&&Right[p]==x) //LR的情况
{
Zag(x);
Zig(x);
}
else if(Right[g]==p&&Left[p]==x) //RL的情况
{
Zig(x);
Zag(x);
}
else if(Right[g]==p&&Right[p]==x) //RR的情况
{
Zag(p);
Zag(x);
}
}
}
s = x;//变为树根
}
//初始化各容器
void Init()
{
memset(Left,0,sizeof(Left));
memset(Right,0,sizeof(Right));
memset(father,0,sizeof(father));
for(int i=0;i<SIZE;i++)
next[i] = i+1;
}
//模拟内存分配函数
int newnode(int d)
{
int p = next[0];
next[0] = next[p];
data[p] = d;
return p;
}
void delnode(int p)
{
Left[p] = Right[p] = father[p] = 0;
next[p] = next[0];
next[0] = p;
}
//*********返回插入结点的编号,以便用来Splay**************//
int BST_insert(int x,int &p)
{
if(!p){ p = newnode(x); return p;}
else if(x < data[p])
{
int q = BST_insert(x,Left[p]);
father[Left[p]] = p;//修改父亲指针
return q;
}
else if(x >= data[p])
{
int q = BST_insert(x,Right[p]);
father[Right[p]] = p;//修改父亲指针
return q;
}
}
//SPT的insert操作
void SPT_insert(int x,int &p)
{
int q = BST_insert(x,p);
Splay(q,p);//伸展
}
int BST_find(int x,int p)
{
if(!p)return 0;//空树
if(x == data[p]) return p;
else if(x < data[p]) return BST_find(x,Left[p]);
else return BST_find(x,Right[p]);
}
int SPT_find(int x,int &s)
{
int q = BST_find(x,s);
if(q)//如果查找成功
Splay(q,s);
return q;
}
int findmax(int &s)
{
int p = s;
while(Right[p]) p = Right[p];
Splay(p,s);
return p;
}
int findmin(int &s)
{
int p = s;
while(Left[p]) p = Left[p];
Splay(p,s);
return p;
}
/*******************************************************/
int join(int &s1,int &s2)
{
father[s1] = father[s2] = 0;//断开与公共先祖结点的连接 ,此步很关键
if(!s1) return s2;
if(!s2) return s1;
int q = findmax(s1);
Right[s1] = s2;
father[s2] = s1;
return s1;
}
void split(int x,int &s,int &s1,int &s2)
{
int p = SPT_find(x,s);
s1 = Left[p];
s2 = Right[p];
}
void remove(int x,int &p)
{
int q = SPT_find(x,p);
if(q){//如果找到了x
int temp = p;
p = join(Left[p],Right[p]);
delnode(temp);
}
}
/****************************************************************/
//辅助函数
void order(int p)
{
if(!p)return;
order(Left[p]);
cout<<data[p]<<endl;
order(Right[p]);
}
void bfs(int p)
{
if(!p)return;
queue<int> q;
q.push(p);
while(!q.empty())
{
int v = q.front();
q.pop();
if(Left[v]) q.push(Left[v]);
if(Right[v]) q.push(Right[v]);
cout<<data[v]<<endl;
}
}
int main()
{
freopen("dataout.txt","w",stdout);
Init();
int ROOT = 0;
SPT_insert(12,ROOT);//build SPT
SPT_insert(8,ROOT);
SPT_insert(2,ROOT);
SPT_insert(7,ROOT);
SPT_insert(13,ROOT);
remove(13,ROOT);
order(ROOT);
cout<<"--------------"<<endl;
bfs(ROOT);
cout<<"-----------"<<endl;
cout<<father[ROOT]<<endl;
cout<<"------------"<<endl;
int s1,s2;
split(7,ROOT,s1,s2);
bfs(s1);
cout<<"---------"<<endl;
bfs(s2);
return 0;
}
分享到:
相关推荐
**Erlang中的Splay Tree实现** Erlang是一种功能强大的并发编程语言,以其轻量级进程、消息传递和容错能力而闻名。在Erlang中实现数据结构可以帮助优化性能,特别是在处理大量数据时。Splay Tree是一种自调整的二叉...
### SplayTree(伸展树)详细解释 #### 基本概念 SplayTree,又称伸展树,是一种自调整的二叉搜索树。它虽然不像其他平衡二叉搜索树那样严格限制树的形状,但通过一种叫做伸展的操作,在访问节点后将其提升到根节点...
- 考虑到C#的面向对象特性,可以设计一个`SplayTree`类,包含树的根节点,并提供`Insert`, `Delete`, `Find`等公共方法。 5. **性能分析**:伸展树的平均性能优于普通的二叉搜索树。虽然最坏情况下的性能与普通BST...
### 伸展树(Splay Tree)概述 伸展树(Splay Tree)是一种自调整的二叉搜索树,由Daniel Sleator和Robert Tarjan在1985年提出。其核心思想是在每次访问节点后,通过一系列的旋转操作将被访问的节点调整到树根的位置...
伸展数的主要难点:展开函数的实现。 基本操作插入、删除、查找都和展开函数相关。 插入:在根处按要插入的元素展开树,如果树中已经存在此节点,则此节点在展开后就是根;如果不存在节点,根处的元素是比欲插入节点...
游戏树展开树的简单实现。 所有函数都具有与 STL 映射函数类似的调用。细节此实现是出于教育目的。 对该库进行了基本测试。 如果您发现错误,请报告它,我会尝试修复它。特征C++11 组件前向迭代器和 const_iterator ...
在"Algorithm-splay_tree.zip"的压缩包内,"splay_tree-master"可能包含一个Splay Tree的实现,包括源代码、示例、测试用例等,供学习和参考。研究这些内容可以帮助深入理解Splay Tree的工作原理以及如何在实际应用...
我们涉及到了五种特定的树型数据结构,它们是BTree(B树)、AVLTree(AVL树)、RBTree(红黑树)、BinarySearchTree(二叉搜索树)以及SPlayTree(自旋搜索树),并且这些数据结构的C++源码实现被包含在一个压缩包内...
快速八叉树 :(非递归)和简单(<1000行代码)实现是直接从Wikipedia改编而成的,使用与相同的API来针对其他树运行基准测试。 该树基于D.Sleator自上而下的展开...S splaytree import SplayTree from 'splaytree'
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由丹尼尔·斯立特Daniel Sleator 和 罗伯特·恩卓·塔扬Robert Endre Tarjan 在1985年发明的。伸展树是一种自...
POJ 3580代码 Splay tree实现
### 伸展树(Splay Tree)详解 #### 一、伸展树简介 **伸展树**(Splay Tree)是一种特殊的二叉搜索树(Binary Search Tree),它能够在平均情况下达到 O(log n) 的时间复杂度,对于插入、查找和删除操作均适用。...
在JavaScript编程环境中,`node-splay-tree`库提供了一个用于创建和操作展开树的实现。 展开树的核心思想是**Splay操作**,它包括三种基本操作:**旋转**(zig,zag,zig-zag,zig-zig),**插入**和**删除**。这三...
在描述中提到的“An solution of a problem using Splay Trees”,这表明该压缩包内的内容可能包含一个程序或代码实现,利用Splay Tree的数据结构解决了一个具体的问题。通常,这样的解决方案会包括以下部分: 1. *...
在`splaytree-master`这个压缩包中,我们可以推测它包含了`splaytree`的源代码实现,`SplayTree`是八卦树的一种优化形式,即自旋树。自旋树是一种自调整的树结构,它通过旋转操作使得最近频繁访问的节点更靠近根部,...
在二叉树的基础上,二叉查找树(Binary Search Tree,BST)是一种特殊的二叉树,其每个节点的值都大于其左子树中的任何节点的值,并小于其右子树中的任何节点的值。这种性质使得二叉查找树在查找特定值时具有较高的...
此实现提供了类似哈希的界面,并且提供了Splay树中通常不存在的几个功能-有效删除通常访问最少的项,并提供额外的快速搜索选项。叶修剪由于八字树倾向于将自身与最常访问的元素一起组织到树的根部,因此最不频繁...
给定一个长度为N的序列,每个序列的长度是一个整数。要支持以下三种操作: 将[L,R]这个区间所有数加上V. 将[L,R]这个区间翻转,例如 1234变成 4321 ...能力有限,实现可能有纰漏,也没有用到lazy_tag
在本实习录入任务中,我们将探讨如何快速地实现和操作八叉树,即“splay tree”。 Splay Tree,又称自旋树或伸展树,是一种自调整的二叉查找树。虽然这里提到的是八叉树,但splay的概念可以扩展到多叉树。它的核心...