伸展树——自顶向下
来源:互联网 发布:f35机动知乎 编辑:程序博客网 时间:2024/06/05 21:09
三种旋转
当我们沿着树向下搜索某个节点X的时候,我们将搜索路径上的节点及其子树移走。我们构建两棵临时的树──左树和右树。
没有被移走的节点构成的树称作中树。在伸展操作的过程中:
1、当前节点X是中树的根。2、左树L保存小于X的节点。
3、右树R保存大于X的节点。
开始时候,X是树T的根,左右树L和R都是空的。
1、zig:
如上图,在搜索到X的时候,所查找的节点比X小,将Y旋转到中树的树根。旋转之后,X及其右子树被移动到右树上。很显然,右树上的节点都大于所要查找的节点。注意X被放置在右树的最小的位置,也就是X及其子树比原先的右树中所有的节点都要小。这是由于越是在路径前面被移动到右树的节点,其值越大。
2、zig-zig:
在这种情况下,所查找的节点在Z的子树中,也就是,所查找的节点比X和Y都小。所以要将X,Y及其右子树都移动到右树中。首先是Y绕X右旋,然后Z绕Y右旋,最后将Z的右子树(此时Z的右子节点为Y)移动到右树中。注意右树中挂载点的位置。
3、zig-zag:
在这种情况中,首先将Y右旋到根。这和Zig的情况是一样的。然后变成上图右边所示的形状。接着,对Z进行左旋,将Y及其左子树移动到左树上。这样,这种情况就被分成了两个Zig情况。这样,在编程的时候就会简化,但是操作的数目增加(相当于两次Zig情况)。
最后,在查找到节点后,将三棵树合并。如图:
将中树的左右子树分别连接到左树的右子树和右树的左子树上。将左右树作为X的左右子树。重新最成了一所查找的节点为根的树。
右连接:将当前根及其右子树连接到右树上。左子结点作为新根。 左连接:将当前根及其左子树连接到左树上。右子结点作为新根。
越是在路径前面被移动到右树的节点,其值越大;越是在路径前面移动到左树的节点,其值越小。
这很显然,右连接,将当前根以及右子树全部连接到右树,即把整课树中值大的一部分移走(大于等于当前根),
后面,在进行右连接,其值肯定小于之前的,所以,要加在右树的左边。
伸展树伪代码
右连接:将当前根及其右子树连接到右树上。左子结点作为新根。 左连接:将当前根及其左子树连接到左树上。右子结点作为新根。 T : 当前的根节点。 Function Top-Down-Splay Do If X 小于 T Then If X 等于 T 的左子结点 Then //zig 右连接 ElseIf X 小于 T 的左子结点 Then //zig-zig T的左子节点绕T右旋 右连接 Else X大于 T 的左子结点 Then //zig-zag 右连接 左连接 EndIf ElseIf X大于 T Then IF X 等于 T 的右子结点 Then 左连接 ElseIf X 大于 T 的右子结点 Then T的右子节点绕T左旋 左连接 Else X小于 T 的右子结点 Then 左连接 右连接 EndIf EndIf While !(找到 X或遇到空节点) 组合左中右树 EndFunction
zig-zag这种情形,可以先按zig处理。第二次循环在进行一次处理。简化代码如下:
Function Top-Down-Splay Do If X 小于 T Then If X 小于 T 的左孩子 Then T的左子节点绕T右旋 EndIf 右连接 Else If X大于 T Then If X 大于 T 的右孩子 Then T的右子节点绕T左旋 EndIf 左连接 EndIf While !(找到 X或遇到空节点) 组合左中右树 EndFuntion
例子
下面是一个查找节点19的例子:
在例子中,树中并没有节点19,最后,距离节点最近的节点18被旋转到了根作为新的根。节点20也是距离节点19最近的节点,但是节点20没有成为新根,这和节点20在原来树中的位置有关系。
如果查找的元素不在树中,则寻找过程中出现空的上一个节点即为根节点。
CPP代码
.h
struct SplayNode{int element;SplayNode *left;SplayNode *right;};class SplayTree{public:SplayTree();~SplayTree();void Insert(int data);void Remove(int data);SplayNode *Find(int data);private:SplayNode *_tree;SplayNode *_Insert(SplayNode *T, int item);SplayNode *_Remove(SplayNode *T, int item);SplayNode *_Splay(SplayNode *X, int Item);SplayNode *_SingleToRight(SplayNode *K2); SplayNode *_SingleToLeft(SplayNode *K2); void _MakeEmpty(SplayNode *root);};
.cpp
SplayTree::SplayTree(){_tree = NULL;}SplayTree::~SplayTree(){_MakeEmpty(_tree);}void SplayTree::Insert(int data){_tree = _Insert(_tree, data);}void SplayTree::Remove(int data){_tree = _Remove(_tree, data);}SplayNode *SplayTree::_SingleToRight(SplayNode *K2) { SplayNode *K1 = K2->left; K2->left = K1->right; K1->right = K2; return K1; } SplayNode *SplayTree::_SingleToLeft(SplayNode *K2) { SplayNode *K1 = K2->right; K2->right = K1->left; K1->left = K2; return K1; } SplayNode *SplayTree::_Splay(SplayNode *X, int item){static struct SplayNode Header;SplayNode *leftTreeMax, *rightTreeMin;Header.left = Header.right = NULL;leftTreeMax = rightTreeMin = &Header;while( X != NULL && item != X->element){if(item < X->element){if(X->left == NULL)break;if(item < X->left->element){X = _SingleToRight(X); } if( X->left == NULL)break; //右连接 rightTreeMin->left = X;rightTreeMin = X;X = X->left;}else{if(X->right == NULL)break;if(item > X->right->element){X = _SingleToLeft(X);}if(X->right == NULL)break; //左连接 leftTreeMax->right = X;leftTreeMax = X;X = X->right;}}leftTreeMax->right = X->left;rightTreeMin->left = X->right;X->left = Header.right;X->right = Header.left;return X;}SplayNode *SplayTree::_Insert(SplayNode *T, int item){static SplayNode* newNode = NULL;if(newNode == NULL){newNode = new SplayNode;}newNode->element = item;if(T == NULL){newNode->left = newNode->right = NULL;T = newNode;}else{T = _Splay(T, item);if(item < T->element){newNode->left = T->left;newNode->right = T;T->left = NULL;T = newNode;}else if(T->element < item){newNode->right = T->right;newNode->left = T;T->right = NULL;T = newNode;}else{delete newNode;}}newNode = NULL;return T;}SplayNode *SplayTree::_Remove(SplayNode *T, int item){SplayNode *newTree;if(T != NULL){T = _Splay(T, item);if(item == T->element){if(T->left == NULL){newTree = T->right;}else{newTree = T->left;newTree = _Splay(newTree, item);newTree->right = T->right;}delete T;T = newTree;}}return T;}void SplayTree::_MakeEmpty(SplayNode *T) { if(T != NULL) { _MakeEmpty(T->left); _MakeEmpty(T->right); delete T; } }SplayNode *SplayTree::Find(int data){_tree = _Splay(_tree, data);if(_tree->element == data)return _tree;elsereturn NULL;}
参考
参考:http://www.cnblogs.com/kernel_hcy/archive/2010/03/17/1688360.html
- 伸展树——自顶向下
- 高级数据结构实现——自顶向下伸展树
- 自顶向下伸展树
- 【伸展树】自顶向下写法
- C++伸展树自顶向下实现
- 《DSAA》 12.1 自顶向下伸展树
- 伸展树 自底向上 自顶向下
- 自顶向下伸展树头文件C语言
- 自顶向下伸展树实现文件C语言
- 伸展树(splay tree)自顶向下的算法
- 伸展树介绍 - 使用自顶向下的调整算法
- 伸展树---(自顶向下的设计)
- 《数据结构与算法分析》伸展树(自顶向下)详解
- 归并排序—自底向上和自顶向下
- 编译原理中的语法分析——自顶向下
- 自顶向下(一)——计算机网络与英特网
- 计算机网络自顶向下——计算机网络与因特网
- 自顶向下语法分析——编译原理
- 动态数组
- RTP/RTCP/RTSP/SIP/SDP 关系(转)
- jQuery-对Radio/CheckBox的操作集合
- 1001. A+B Format (20)
- JDK动态代理(一)
- 伸展树——自顶向下
- 《计算机网络》之网络层
- 《盗墓笔记》解谜!
- 9个offer,12家公司,35场面试,从微软到谷歌,应届计算机毕业生的2012求职之路
- Proxy动态代理(二)
- 启动的shell时,属于root用户
- super(true) destroyApp(true) 部分英文缩写
- C函数与汇编函数之间参数及返回值传递方法
- Centos6.3安装OpenStack的Folsom版本(2)