您的位置:首页 > 其它

伸展树(splay tree)实现

2012-08-31 11:08 232 查看
前面讲解了平衡二叉查找树,注意到一个结点被访问后,接下来很有可能被再次访问,所以可以采取把最近访问的结点上移(比如说移动到根结点),方便以下访问。这次要讲解的伸展树就是来解决该问题的。

伸展树又称自适应查找树,它的各种操作平均复杂度为O(lgn),其复杂度边界是均摊的。虽然某次操作可能需要代价O(n),但是连续M次操作的代价为O(M*lgn)。

伸展树的最核心的操作就是伸展,插入、删除、查找都要用到伸展操作。一般来说,伸展操作可以从搜索路径上最后一个结点开始,自底向上进行左旋和右旋操作,但是该方式需要知道父节点信息,而计算父节点或存储父节点需要较大的开销。于是一般采用自顶向下的实现方式。从根结点开始搜索某一结点x,不断进行左旋和右旋,同时把大于x的结点接到树R的左子树中,把小于x的结点接到树L的右子树上,直到查找路径的最后一个结点。然后把树进行重组,就得到了伸展后的树。

详细原理请看参考资料,参考资料[1][2]都对原理进行了详尽的阐述,并提供了实现。下面直接给出代码,代码中有详细注释。

#include <cstdlib>
#include <iostream>

using namespace std;

typedef struct BinNode
{
int data;
struct BinNode* left;
struct BinNode* right;
}BinNode, *BiTree;

BinNode* splay(int i, BinNode* t)
{
BinNode N;				//哨位结点
BinNode* L;
BinNode* R;
BinNode* y;

//	if(t == NULL)		//空树
//		return t;
N.left = N.right = NULL;
L = R = &N;				//指针L和R初始指向哨位结点N

while(true)
{
if(i < t->data)
{
if(t->left != NULL && i < t->left->data)//右旋转
{
y = t->left;
t->left = y->right;
y->right = t;
t = y;
}
if(t->left == NULL)
{
break;
}
R->left = t;	//右链接,把t挂接为R的左子树
R = t;			//t为新的R
t = t->left;	//在t的左子树中继续查找
}
else if(i > t->data)
{
if(t->right != NULL && i > t->right->data)//左旋转
{
y = t->right;
t->right = y->left;
y->left = t;
t = y;
}
if(t->right == NULL)
{
break;
}
L->right = t;	//左链接,把t挂接为L的右子树
L = t;			//t为新的L
t = t->right;	//在t右子树中继续查找
}
else				//与当前根结点元素相同,重复
{
break;
}
}

L->right = t->left;		//重新组合
R->left = t->right;
t->left = N.right;		//N.right为实际左子树的根
t->right = N.left;		//N.left为实际右子树的根
return t;
}

BinNode* insert(int i, BinNode* t)
{
BinNode* newNode = new BinNode;//开辟一个新结点
newNode->data = i;
newNode->left = newNode->right = NULL;

if(t == NULL)			//t为空树
{
return newNode;
}

t = splay(i,t);			//返回伸展后的新根结点
if(i < t->data)			//欲插入元素在树中不存在,且小于根结点元素值
{
newNode->left = t->left;
newNode->right = t;
t->left = NULL;
return newNode;
}
else if(i > t->data)	//欲插入元素在树中不存在,且小于根结点元素值
{
newNode->right = t->right;
newNode->left = t;
t->right = NULL;
}
else					//欲插入元素在树中存在,即等于根结点元素值
{
delete newNode;
return t;
}
}

BinNode* remove(int i, BinNode* t)
{
BinNode* newRoot = NULL;

if(t == NULL)			//空树
{
return t;
}

t = splay(i,t);

if(i == t->data)		//找到该元素结点
{
if(t->left == NULL)	//根结点左子树为空
{
newRoot = t->right;

}
else
{
newRoot = splay(i, t->left);//newRoot必然指向t的左结点中最大的结点,
//也就是伸展前t的前驱结点
newRoot->right= t->right;
}
delete t;
return newRoot;
}
return t;				//树中不存在该元素
}

BinNode* search(int i, BinNode* t, bool& exist)
{
exist = false;
if(t == NULL)
return NULL;
t = splay(i, t);
if(i == t->data)
{
exist = true;
}
return t;
}

void inOrder(BinNode* t)
{
if(t)
{
inOrder(t->left);
cout<<t->data<<" ";
inOrder(t->right);
}
}
void preOrder(BinNode* t)
{
if(t)
{
cout<<t->data<<" ";
preOrder(t->left);
preOrder(t->right);
}
}

void printTree(BinNode* t)
{
cout<<"preOrder: "<<endl;
preOrder(t);
cout<<endl;
cout<<"inOrder: "<<endl;
inOrder(t);
cout<<endl<<endl;
}

int main(int argc, char *argv[])
{
BinNode* root = NULL;
bool res = false;
//insert
for(int i=20; i>0; i--)
root = insert(i,root);
cout<<"after insert: "<<endl;
printTree(root);

//remove
for(int i= 1; i<20; i += 2)
root = remove(i,root);
cout<<"after remove :"<<endl;
printTree(root);

//search
cout<<"search elements: "<<endl;
for(int i=1; i<20; i++)
{
root = search(i,root,res);
if(res)
{
cout<<"("<<i<<","<<"yes"<<")"<<endl;;
}
else
{
cout<<"("<<i<<","<<"no"<<")"<<endl;
}
}
cout<<"after search: "<<endl;
printTree(root);

system("PAUSE");
return EXIT_SUCCESS;
}


参考资料:
[1]Data Structures and Algorithm Analysis in C++(third editon) (数据结构与算法分析C++描述,第3版 )

[2一篇博客文章:/article/5853733.html

[3]详细C和java实现:http://www.link.cs.cmu.edu/link/ftp-site/splaying/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: