伸展树
来源:互联网 发布:sql 数据库置疑 编辑:程序博客网 时间:2024/05/16 16:53
伸展树,是一种二叉排序树。它可以保证从空树开始任意连续M次对树的操作最多花费O(MlogN)时间。虽然这种保证并不排除任意一次操作花费O(N)时间的可能,而且这样的界也也不如每次操作最坏情形的界O(logN)那么短,但是实际效果是一样的:不存在坏的输入序列。一般来说,当M次操作的序列总的最坏情形运行时间为O(MF(N))时,我们说它的摊还(amortized)运行时间为O(F(N))。
伸展树相比AVL树不需要额外的平衡因子或者高度等信息,在访问符合一定分布的数据集时性能尤佳,而且实现自顶向下的伸展树相对简单。
一,基本的自底向上伸展树
伸展操作主要是将最近访问的结点通过一系列的旋转置于树的顶端。
在旋转的时候,可以分为三种情况:
1、zig情况。
X是查找路径上我们需要旋转的一个非根节点。
如果X的父节点是根,那么我们用下图所示的方法旋转X到根:
这和一个普通的单旋转相同。
2、zig-zag情况。
在这种情况中,X有一个父节点P和祖父节点G(P的父节点)。X是右子节点,P是左子节点,或者反过来。这个就是双旋转。
先是X绕P左旋转,再接着X绕G右旋转。
如图所示:
3、zig-zig情况。
这和前一个旋转不同。在这种情况中,X和P都是左子节点或右子节点。
先是P绕G右旋转,接着X绕P右旋转。
如图所示:
下面是一个例子,旋转节点c到根上。
二、基本伸展树操作:
1、插入:
当一个节点插入时,伸展操作将执行。因此,新插入的节点在根上。
2、查找:
如果查找成功(找到),那么由于伸展操作,被查找的节点成为树的新根。
如果查找失败(没有),那么在查找遇到NULL之前的那个节点成为新的根。也就是,如果查找的节点在树中,那么,此时根上的节点就是距离这个节点最近的节点。
3、查找最大最小:
查找之后执行伸展。
4、删除最大最小:
a)删除最小:
首先执行查找最小的操作。
这时,要删除的节点就在根上。根据二叉查找树的特点,根没有左子节点。
使用根的右子结点作为新的根,删除旧的包含最小值的根。
b)删除最大:
首先执行查找最大的操作。
删除根,并把被删除的根的左子结点作为新的根。
5、删除:
将要删除的节点移至根。
删除根,剩下两个子树L(左子树)和R(右子树)。
使用DeleteMax查找L的最大节点,此时,L的根没有右子树。
使R成为L的根的右子树。
如下图示:
三、自顶向下的伸展树:
在自底向上的伸展树中,我们需要求一个节点的父节点和祖父节点,因此这种伸展树难以实现。因此,我们可以构建自顶向下的伸展树。
当我们沿着树向下搜索某个节点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的左右子树。重新最成了一所查找的节点为根的树。
下面是一个查找节点19的例子:
在例子中,树中并没有节点19,最后,距离节点最近的节点18被旋转到了根作为新的根。节点20也是距离节点19最近的节点,但是节点20没有成为新根,这和节点20在原来树中的位置有关系。
代码:
#include <iostream>#include <iomanip>#include <vector>#include <queue>using namespace std;typedef struct SplayTreeNode * SplayTree;typedef struct SplayTreeNode{int data;SplayTreeNode *lchild,*rchild;} SplayTreeNode;void BuildSplayTree(SplayTree *T){int item;cin>>item;if(item==-1){*T = NULL;}else {*T = new SplayTreeNode;(*T)->data = item; BuildSplayTree(&((*T)->lchild));BuildSplayTree(&((*T)->rchild));}}SplayTree SingleRotateWithLeft(SplayTree x){/* x has left child y */SplayTree y;y = x->lchild;x->lchild = y->rchild;y->rchild = x;return y;}SplayTree SingleRotateWithRight(SplayTree x){/* x has right child y */SplayTree y;y = x->rchild;x->rchild = y->lchild;y->lchild = x;return y;}SplayTree DoubleRotateWithLeft(SplayTree x){/* x has left child x->lchild and also x->lchild has a right child x->lchild->right*/x->lchild = SingleRotateWithRight(x->lchild);return SingleRotateWithLeft(x);}SplayTree DoubleRotateWithRight(SplayTree x){/* x has right child x->rchild and also x->rchild has a left child x->rchild->lchild*/x->rchild = SingleRotateWithLeft(x->rchild);return SingleRotateWithRight(x);}SplayTree Splay(int key,SplayTree X){/* simple top down splay, not requiring key in the tree Xwhat it does is as described below */SplayTreeNode N;SplayTree left,right;if (X == NULL)return X;N.lchild = N.rchild = NULL;left = right = &N;while (key != X->data) {if (key < X->data){if (X->lchild == NULL) break;if( key < X->lchild->data) {/*小于左支路上连续的两个结点*/ X = SingleRotateWithLeft(X);}/*旋转之后看停止条件是否满足*/if (X->lchild == NULL)break;right->lchild = X;right = X;X = X->lchild;}else {if ( X->rchild == NULL)break;if ( key > X->rchild->data) {/*大于右支路上连续的两个结点*/ X = SingleRotateWithRight(X); }/*旋转后看是否满足停止条件*/ if (X->rchild == NULL)break;left->rchild = X;left = X;X = X->rchild;}}left->rchild = X->lchild;right->lchild = X->rchild;X->lchild = N.rchild;X->rchild = N.lchild;return X;} bool SplaySearch(int key, SplayTree *T){SplayTree t = *T;while (t != NULL) {if (key < t->data)t = t->lchild;else if (key > t->data)t = t->rchild;else {*T = Splay(key,*T);return true;}}return false;} SplayTree SplayInsert(int key,SplayTree T){SplayTree t;t = new SplayTreeNode;t->data = key;t->lchild = t->rchild = NULL; if (T == NULL) {T = t;}else {T = Splay(key,T);if (key < T->data) {t->lchild = T->lchild;t->rchild = T;T->lchild = NULL;T = t;}else {if (T->data <key) {t->rchild = T->rchild;t->lchild = T;T->rchild = NULL;T = t;}else {delete t;}}} return T;}SplayTree SplayDelete(int key, SplayTree T){SplayTree t;if (T != NULL) {T = Splay(key, T);if (key == T->data) {if (T->lchild == NULL)t = T->rchild;else {t = T->lchild;t = Splay(key,t);t->rchild = T->rchild;}delete T;T = t;}}return T;}inline int max(int a,int b){return a>b?a:b;}int Height(SplayTree T){if (T == NULL)return 0;elsereturn 1 + max(Height(T->lchild), Height(T->rchild));}void MakeMat(SplayTree T,int root_x,int root_y,int step,int **m){int lChildPos,rChildPos;lChildPos = root_x - step;rChildPos = root_x + step;if (T == NULL) return;else{m[root_y][root_x] = 1;MakeMat(T->lchild,lChildPos,root_y+1,step>>1,m);MakeMat(T->rchild,rChildPos,root_y+1,step>>1,m);}}void SplayTreeDisplay(SplayTree T){if(T == NULL)return;/* init placehold flags m[h][len] */int h = Height(T);int len = (1<<h) - 1;int row = h; int **m = new int*[row];for(int i= 0;i<row;i++){m[i] = new int[len];memset(m[i],0,len*sizeof(int));}/* get level order traversal sequence */vector<SplayTree> v;queue<SplayTree> q;queue<SplayTree> qt;q.push(T);SplayTree pt;while(!q.empty()){pt = q.front();if (pt->lchild != NULL)q.push(pt->lchild);if(pt->rchild != NULL)q.push(pt->rchild);v.push_back(pt);q.pop();}/* generate output matrix plus '/' and '\\' m[2*h-1][len] */MakeMat(T,len>>1,0,len+1>>2,m);/* generate output */int cnt = 0;int width = 1;for(int i = 0; i < row; i++){for(int j = 0; j < len; j++){if(m[i][j]){//if (i & 1) //cout<<setw(width)<<char(m[i][j]);//else//cout<<setw(width)<<char(m[i][j]);//cout<<setw(width)<<m[i][j];cout<<(v[cnt])->data;cnt++;}elsecout<<setw(width)<<' ';}cout<<endl;}}int main(){SplayTree T = NULL;int i;//BuildSplayTree(&T); //SplayTreeDisplay(T);int a[] = {4,5,3,1,7,2,6}; for(i = 0; i < 6; i++) {cout<<"Key = "<<a[i]<<" inserting: "<<endl;T = SplayInsert(a[i],T);SplayTreeDisplay(T);cout<<"--------------------------------------------""--------------------"<<endl;}for(i = 0; i < 6; i++) {cout<<"Key = "<<a[i]<<" searching: "<<endl;SplaySearch(a[i],&T);SplayTreeDisplay(T);cout<<"--------------------------------------------""--------------------"<<endl;}for(i = 0; i < 6; i++) {cout<<"Key = "<<a[i]<<" deleting: "<<endl;T = SplayDelete(a[i],T);SplayTreeDisplay(T);cout<<"--------------------------------------------""--------------------"<<endl;}cout<<"Key = "<<19<<" deleting: "<<endl;T = SplayDelete(19,T);SplayTreeDisplay(T);cout<<"--------------------------------------------""--------------------"<<endl;}
测试输出:
Key = 4 inserting: 4----------------------------------------------------------------Key = 5 inserting: 5 4 ----------------------------------------------------------------Key = 3 inserting: 3 4 5----------------------------------------------------------------Key = 1 inserting: 1 3 4 5----------------------------------------------------------------Key = 7 inserting: 7 5 3 1 4 ----------------------------------------------------------------Key = 2 inserting: 2 1 5 3 7 4 ----------------------------------------------------------------Key = 4 searching: 4 2 5 1 3 7----------------------------------------------------------------Key = 5 searching: 5 4 7 2 1 3 ----------------------------------------------------------------Key = 3 searching: 3 2 4 1 5 7----------------------------------------------------------------Key = 1 searching: 1 2 3 4 5 7----------------------------------------------------------------Key = 7 searching: 7 2 1 4 3 5 ----------------------------------------------------------------Key = 2 searching: 2 1 7 4 3 5 ----------------------------------------------------------------Key = 4 deleting: 3 2 7 1 5 ----------------------------------------------------------------Key = 5 deleting: 3 2 7 1 ----------------------------------------------------------------Key = 3 deleting: 2 1 7----------------------------------------------------------------Key = 1 deleting: 2 7----------------------------------------------------------------Key = 7 deleting: 2----------------------------------------------------------------Key = 2 deleting: ----------------------------------------------------------------Key = 19 deleting: ----------------------------------------------------------------
REF:
1,http://www.cnblogs.com/kernel_hcy/archive/2010/03/17/1688360.html
2,数据结构与算法分析--C语言描述 Mark Allen Weiss
3,http://digital.cs.usu.edu/~allan/DS/Notes/Ch22.pdf
- 伸展树:双层伸展
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- 伸展树
- cas入门之二十八:services管理控制台
- 内存泄露(一)
- D - I Think I Need a Houseboat(1.3.1)
- c语言字符串 数字转换函数大全(转载)
- poj 2663 压缩DP
- 伸展树
- FPGA机器学习之stanford机器学习第十六堂
- boa服务器及cgic库的安装及使用
- hdu 1394 暴力
- 在海思3511上面实现wifi模块变成ap站点功能+wifi rt3070驱动的移植
- (未完成)matlab--矩阵运算技巧
- 需要手工register logfile的情况
- TQ210_裸机编程(三)——串口通信
- 第三章 数据预处理