伸展树--java
文字转载自:http://www.cnblogs.com/vamei
代码转载自:http://www.blogjava.net/javacap/archive/2007/12/19/168627.html
我们讨论过,树的搜索效率与树的深度有关。二叉搜索树的深度可能为n,这种情况下,每次搜索的复杂度为n的量级。AVL树通过动态平衡树的深度,单次搜索的复杂度为log(n) (以上参考纸上谈兵 AVL树)。我们下面看伸展树(splay tree),它对于m次连续搜索操作有很好的效率。
伸展树会在一次搜索后,对树进行一些特殊的操作。这些操作的理念与AVL树有些类似,即通过旋转,来改变树节点的分布,并减小树的深度。但伸展树并没有AVL的平衡要求,任意节点的左右子树可以相差任意深度。与二叉搜索树类似,伸展树的单次搜索也可能需要n次操作。但伸展树可以保证,m次的连续搜索操作的复杂度为mlog(n)的量级,而不是mn量级。
具体来说,在查询到目标节点后,伸展树会不断进行下面三种操作中的一个,直到目标节点成为根节点 (注意,祖父节点是指父节点的父节点)
1. zig: 当目标节点是根节点的左子节点或右子节点时,进行一次单旋转,将目标节点调整到根节点的位置。
zig
2. zig-zag: 当目标节点、父节点和祖父节点成"zig-zag"构型时,进行一次双旋转,将目标节点调整到祖父节点的位置。
zig-zag
3. zig-zig:当目标节点、父节点和祖父节点成"zig-zig"构型时,进行一次zig-zig操作,将目标节点调整到祖父节点的位置。
zig-zig
单旋转操作和双旋转操作见AVL树。下面是zig-zig操作的示意图:
zig-zig operation
在伸展树中,zig-zig操作(基本上)取代了AVL树中的单旋转。通常来说,如果上面的树是失衡的,那么A、B子树很可能深度比较大。相对于单旋转(想一下单旋转的效果),zig-zig可以将A、B子树放在比较高的位置,从而减小树总的深度。
下面我们用一个具体的例子示范。我们将从树中搜索节点2:
Original
zig-zag (double rotation)
zig-zig
zig (single rotation at root)
上面的第一次查询需要n次操作。然而经过一次查询后,2节点成为了根节点,树的深度大减小。整体上看,树的大部分节点深度都减小。此后对各个节点的查询将更有效率。
伸展树的另一个好处是将最近搜索的节点放在最容易搜索的根节点的位置。在许多应用环境中,比如网络应用中,某些固定内容会被大量重复访问(比如江南style的MV)。伸展树可以让这种重复搜索以很高的效率完成。
java代码:
package algorithms.tree; /**
* @author yovn
*
*/
public class SplayTree<E extends Comparable<E>> extends DefaultBSTree<E> implements BSTree<E> { static class SplayTreeNode<E extends Comparable<E>> extends BSTNode<E>
{ SplayTreeNode<E> parent; SplayTreeNode(SplayTreeNode<E> parent,E key) {
super(key);
this.parent=parent; } } @Override
public boolean delete(E ele) {
return _delete((SplayTreeNode<E>)root,ele);
} private boolean _delete(SplayTreeNode<E> pointer, E ele) {
int cmp=ele.compareTo(pointer.key);
while(cmp!=0)
{
if(cmp<0)
{
pointer=(SplayTreeNode<E>)pointer.left;
}
else
{
pointer=(SplayTreeNode<E>)pointer.right;
}
if(pointer==null)return false;
cmp=ele.compareTo(pointer.key);
}
//okay find it
SplayTreeNode<E> p=pointer.parent;
if(pointer.left==null)
{
if(p!=null)
{
keep_right(pointer);
splay(p);
}
else {
root = p.right;
if(root!=null)((SplayTreeNode<E>)root).parent=null;
} }
else if(pointer.right==null)
{
if(p!=null)
{
keep_left(pointer);
splay(p);
}
else {
root = p.left;
if(root!=null)((SplayTreeNode<E>)root).parent=null;
}
}
else
{
SplayTreeNode<E> todo=(SplayTreeNode<E>)pointer.left;
SplayTreeNode<E> todoP=null;
while(todo.right!=null)
{
todoP=todo;
todo=(SplayTreeNode<E>)todo.right;
}
pointer.key=todo.key;
if (todoP != null) {
todoP.right = todo.left;
if (todo.left != null)
((SplayTreeNode<E>) todo.left).parent = todoP;
}
else
{
pointer.left=null;
}
splay(pointer.parent); }
return true;
} private void keep_left(SplayTreeNode<E> pointer) {
SplayTreeNode<E> p=pointer.parent;
if(p.left==pointer)
{
p.left=pointer.left;
if(p.left!=null)((SplayTreeNode<E>)p.left).parent=p;
}
else if(p.right==pointer)
{
p.right=pointer.left;
if(p.right!=null)((SplayTreeNode<E>)p.right).parent=p;
} } private void keep_right(SplayTreeNode<E> pointer) {
SplayTreeNode<E> p=pointer.parent;
if(p.left==pointer)
{
p.left=pointer.right;
if(p.left!=null)((SplayTreeNode<E>)p.left).parent=p;
}
else if(p.right==pointer)
{
p.right=pointer.right;
if(p.right!=null)((SplayTreeNode<E>)p.right).parent=p;
} } protected void splay(SplayTreeNode<E> cur) { if(cur==null)return; while(cur!=root)
{
if(cur.parent==root)
{
//single Rotation
SingleRotation(cur,cur.parent);
cur.parent=null;
root=cur; }
else if(cur.parent.left==cur&&cur.parent.parent.left==cur.parent)
{ cur=Left_ZigZig(cur,cur.parent,cur.parent.parent); }
else if(cur.parent.right==cur&&cur.parent.parent.right==cur.parent)
{
cur=Right_ZigZig(cur,cur.parent,cur.parent.parent);
}
else if(cur.parent.left==cur&&cur.parent.parent.right==cur.parent)
{
cur=RL_ZigZag(cur,cur.parent,cur.parent.parent);
}
else if(cur.parent.right==cur&&cur.parent.parent.left==cur.parent)
{
cur=LR_ZigZag(cur,cur.parent,cur.parent.parent);
}
else
{
System.out.println("Oooops!!!");
}
}
} private SplayTreeNode<E> LR_ZigZag(SplayTreeNode<E> cur,
SplayTreeNode<E> p, SplayTreeNode<E> g) {
SplayTreeNode<E> gp=g.parent; g.left=cur.right;
setParent(cur.right,g); g.parent=cur;
cur.right=g; p.right=cur.left;
setParent(cur.left,p); p.parent=cur;
cur.left=p;
if(gp!=null)
{
if(gp.left==g)
{
gp.left=cur;
}
else
{
gp.right=cur; }
}
else root=cur;
cur.parent=gp;
return cur;
} private SplayTreeNode<E> RL_ZigZag(SplayTreeNode<E> cur,
SplayTreeNode<E> p, SplayTreeNode<E> g) {
SplayTreeNode<E> gp=g.parent; g.right=cur.left;
setParent(cur.left,g); g.parent=cur;
cur.left=g; p.left=cur.right;
setParent(cur.right,p); p.parent=cur;
cur.right=p;
if(gp!=null)
{
if(gp.left==g)
{
gp.left=cur;
}
else
{
gp.right=cur; }
}
else root=cur;
cur.parent=gp;
return cur;
} protected SplayTreeNode<E> Right_ZigZig(SplayTreeNode<E> cur, SplayTreeNode<E> p,
SplayTreeNode<E> g) {
SplayTreeNode<E> gp=g.parent; g.right=p.left;
setParent(p.left,g); p.right=cur.left;
setParent(cur.left,p); g.parent=p;
p.left=g; p.parent=cur;
cur.left=p;
if(gp!=null)
{
if(gp.left==g)
{
gp.left=cur;
}
else
{
gp.right=cur; }
}
else root=cur;
cur.parent=gp;
return cur; } protected SplayTreeNode<E> Left_ZigZig(SplayTreeNode<E> cur, SplayTreeNode<E> p,
SplayTreeNode<E> g) {
SplayTreeNode<E> gp=g.parent;
g.left=p.right;
setParent(p.right,g); g.parent=p;
p.right=g; p.left=cur.right;
setParent(cur.right,p); p.parent=cur;
cur.right=p;
if(gp!=null)
{
if(gp.left==g)
{
gp.left=cur;
}
else
{
gp.right=cur; }
}
else root=cur;
cur.parent=gp;
return cur; } final void setParent(BSTNode<E> c, BSTNode<E> p) {
if(c!=null)((SplayTreeNode<E>)c).parent=(SplayTreeNode<E>)p; } private void SingleRotation(SplayTreeNode<E> cur, SplayTreeNode<E> p) {
if(p.left==cur)
{ p.left=cur.right;
if(cur.right!=null)((SplayTreeNode<E>)cur.right).parent=p;
cur.right=p;
p.parent=cur; }
else if(p.right==cur)
{
p.right=cur.left;
if(cur.left!=null)((SplayTreeNode<E>)cur.left).parent=p;
cur.left=p;
p.parent=cur; } } @Override
public void insert(E ele) { if (root == null) {
root = new SplayTreeNode<E>(null,ele);
return;
}
_insert((SplayTreeNode<E>)root,ele);
} private final void _insert(SplayTreeNode<E> pointer,E ele)
{ int cmp=pointer.key.compareTo(ele);
if(cmp==0)
{
throw new IllegalArgumentException();
} if(cmp>0)
{
if(pointer.left==null)
{
pointer.left =new SplayTreeNode<E>(pointer,ele);
splay((SplayTreeNode<E>)pointer.left);
return;
}
_insert((SplayTreeNode<E>)pointer.left,ele); }
else
{
if(pointer.right==null)
{
pointer.right=new SplayTreeNode<E>(pointer,ele);
splay((SplayTreeNode<E>)pointer.right);
return ;
}
_insert((SplayTreeNode<E>)pointer.right,ele);
}
} @Override
public boolean search(E ele) {
return _search((SplayTreeNode<E>)root,ele);
} private boolean _search(SplayTreeNode<E> pointer, E ele) {
if(pointer==null)return false;
int cmp=pointer.key.compareTo(ele);
if(cmp==0)
{
splay(pointer);
return true;
} if(cmp>0)
{ return _search((SplayTreeNode<E>)pointer.left,ele); }
else
{ return _search((SplayTreeNode<E>)pointer.right,ele);
}
} /**
*
*/
public SplayTree() { } }
伸展树java代码
伸展树--java的更多相关文章
- 伸展树(三)之 Java的实现
概要 前面分别通过C和C++实现了伸展树,本章给出伸展树的Java版本.基本算法和原理都与前两章一样.1. 伸展树的介绍2. 伸展树的Java实现(完整源码)3. 伸展树的Java测试程序 转载请注明 ...
- 伸展树(一)之 图文解析 和 C语言的实现
概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...
- 伸展树(二)之 C++的实现
概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
- 数据结构(二) --- 伸展树(Splay Tree)
文章图片和代码来自邓俊辉老师课件 概述 伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由丹尼尔·斯立特Daniel Sleator ...
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- 纸上谈兵:伸展树(splay tree)
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...
- SplayTree伸展树的非递归实现(自底向上)
Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...
- hdu1890 伸展树(区间反转)
对于大神来说这题是水题.我搞这题花了快2天. 伸展树的优点有什么,就是树不管你怎么旋转序列是不会改变得,并且你要使区间反转,只要把第k大的点转到根结点,那么它的左子树就是要交换的区间[l,r),然后交 ...
随机推荐
- jquery实战第一讲---概述及其入门实例
就在5月28号周四下午五点的时候,接到xxx姐姐的电话,您是xxx吗?准备一下,周五上午八点半去远洋面试,一路风尘仆仆,颠颠簸簸,由于小编晕车,带着晕晕乎乎的脑子,小编就稀里糊涂的去面试了,温馨提醒, ...
- 06_NoSQL数据库之Redis数据库:Redis的高级应用之登录授权和主从复制
Redis高级实用特征 安全性(登录授权和登录后使用auth授权) 设置客户端连接后进行任何其他指定前需要使用的密码. 警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户 ...
- JSP连接MySQL时出现--错误:Access denied for user 'root'@'localhost' (using password: YES)'解决方案
用代码进行用户验证的时候总是出现这个错误,翻译一下,应该是root用户的是权限的问题没有放开. 那就想办法解决一下吧,具体的来说可以有这样的几种方式. 解决方法,首先想到的是先重启一下MySQL服务吧 ...
- C语言如何分离一个数的高低位,如何将2个字节变成一个字节
关于这个概念,是我从工作中学习的,虽然在读书的时候就应该要掌握,但是在开发中,这项技能尤其重要.我是做嵌入式开发的,在嵌入式开发过程中,如何对数据操作必然是不可缺少的问题,接下来,我们来看一个例子: ...
- 【Python】Shell MD5使用的那些事
MD5 应该是用的非常多的算法,就自己使用经验说说吧. 场景 算法层面不多说了,维基百科,还有很多文章都有说明. 主要用过的场景 密码存储,现在基本没怎么有使用的了,毕竟破解容易了很多 API校验,现 ...
- VC工程的.gitignore模板
VC工程的.gitignore模板 文件内容如下: #====================================== # .gitignore # # 2015-01-09 create ...
- unity 球体表面平均分割点
之前看了别人的一份源码,讲到了球体表面平均分割点,于是也好奇去查了一下算法,自己写不出来,借用算法在unity写了一个小demo using UnityEngine; using System.Col ...
- OpenCV 透视变换实例
参考文献: http://www.cnblogs.com/self-control/archive/2013/01/18/2867022.html http://opencv-code.com/tut ...
- Oracle EBS订单的流程(Order->AR)
from:http://blog.csdn.net/pan_tian/article/details/7693447 基本流程 创建订单 路径:Order Management > Orders ...
- 推荐一些用CRF做图像语义分割的资源
原文地址:http://blog.sina.com.cn/s/blog_5309cefc01014nri.html 首先是code,以前找了很多,但发现比较好用的有: 1. Matlab版的UGM:h ...