130409总结——平衡树
其实到现在为止Treap还没写成功过(网上是指针,就照着指针写。。。。球了呗。。。)
不过后来还好,SBT是数组的,理解后想改成指针(看起来多好看的),是在无力啊。。。
想想还是算了,就数组吧,不容易出错
1.二叉查找树(二叉搜索树)BST
1.1基本思想
其实思想很简单,就是建立一颗二叉树,左子树都小于根,右子树都大于根,来实现快速查找(其实很慢。。。)
1.2插入
插入X,如果X<当前节点的值(key),就把X插入左子树,否则插入右子树(等于也在右子树,方便且不容易出错)
1.3查找
如果要查找一个数X,如果X<当前key,就在左子树找,否则就在当前节点或者右子树找
弊端
前面说这个似快非快是有道理的,比如一个递增序列,X1插入跟,X2进入右子树,X3进入右子树的右子树,。。。。,这样这棵树就退化成一条链了!
所以我们需要实现平衡!实现严格log2N!
2.随机二叉查找树Treap
顾名思义,Treap= Tree + heap,所以也称作“树堆”
前面说了BST退化的原因在于树的根固定了,儿子有可能一直往一边跑,那我们可不可以通过变换把树平衡呢?先看下图
我们可以通过把2或3给dia起来实现树的平衡,如下图
而Treap的思想就是给每个节点多维护一个附加信息fix,给它一个随机值,然后在保证key为二叉查找树的基础上再给fix建立一个小(大)根堆,由于随机数是大致平均的,所以我们也可以实现大致的平衡,虽然不是严格log2N,但也可以保证快速了,还有就是代码比接下来要说的SBT短
操作都差不多。。。。。
3.SizeBalanced Tree
3.1基本思想
和Treap差不多,都是想办法让树平衡,不过Treap额外维护了一个没用的fix,并且还要靠RP,万一临考前RP不好就球了
而SBT的核心思想就是Maintain函数,它不借助额外的信息,我们说树不平衡就是说某个子树的节点数(size)多了,所以我们就可以借助这个size来使这个树左右平衡!
3.2存储结构
可以开结构体,但是写出来代码很长(后面题目里面有一份是结构体的,很蛋疼。。。。)
所以还是开数组方便些
int S[N],L[N],R[N],A[N];//分别表示size,左儿子,右儿子,和当前key
3.3Maintain函数
为了描述方便用S[]表示size,L[]表示左子树,R[]表示右子树
Maintain分两类
-
调整右子树,就比较S[R[R[p]]]和S[L[p]],如果前者大,就把p左旋,树就平衡了;否则就再比较S[R[L[p]]]和S[L[p]],如果前者大,就先把R[p]右旋,再把p左旋,整棵树就平衡了;否则return
-
调整左子树就与上面完全相反
通过上面的分析我们可以得知,核心思想就是把Size大的尽量向上走
void maintain(int &p,bool flag) //flag为true表示调整右子树
{
if(flag)
{
if(S[R[R[p]]]>S[L[p]]) rotate_left(p);
else if(S[R[L[p]]]>S[L[p]])
{
rotate_right(R[p]);
rotate_left(p);
}
else return;
}
else{
if(S[L[L[p]]]>S[R[p]]) rotate_right(p);
else if(S[L[R[p]]]>S[R[p]])
{
rotate_left(L[p]);
rotate_right(p);
}
else return;
}
maintain(L[p],0);
maintain(R[p],1);
maintain(p,1);
maintain(p,0);
}
核心模块完了其他就好写了
3.4左旋右旋
void rotate_left(int &x)
{
int y=R[x];
R[x]=L[y];
L[y]=x;
S[y]=S[x];
S[x]=S[L[x]]+S[R[x]]+1;
x=y;
}
void rotate_right(int &x)
{
int y=L[x];
L[x]=R[y];
R[y]=x;
S[y]=S[x];
S[x]=S[L[x]]+S[R[x]]+1;
x=y;
}
3.5插入
void insert(int &p,int k)
{
if(!p) {p=++total;init(p,k);}
else{
S[p]++;
if(k<A[p]) insert(L[p],k);
else insert(R[p],k);
maintain(p,k>=A[p]);
}
}
3.6第K大(整个区间)
int kth(int &p,int k)
{
int tmp=S[L[p]]+1;
if(k==tmp) return A[p];
else if(k<tmp) return kth(L[p],k);
else return kth(R[p],k-tmp);
}
3.7找最值
显然,最值肯定出现在整棵树最左(右)
int getmin()
{
int x;
for(x=root ;L[x];x= L[x]);
return A[x];
}
int getmax()
{
int x;
for(x=root ;R[x];x=R[x]);
return A[x];
}
3.8删除
删除操作要是题目要求而写的很不同,所以就不写了
差不多就这些了。。。
目前只做过一道SBT题目(存储方式结构体和数组都有)
【SBT】[NOI2004]郁闷的出纳员cashierhttp://blog.csdn.net/jiangzh7/article/details/8759397