额,今天先更左旋右旋,当然加强版的线段树正在来的路上。。。
左旋右旋,就是说可以用来平衡二叉树,加强二叉树的效率。
如果阅读上有些困难,建议画一个图来看。
#include<cstdio>
#include<cstdlib>
using namespace std;
int n;
struct node
{
int d;
int rnd;
node *parent;
node *ch[2];
}pool[100100],*root;
void insert (node *r,node *p)//建树
{
if(r->d >= p->d)
{
if(r->ch[0]==0)
r->ch[0]=p,p->parent=r;
else
insert(r->ch[0],p);
}
else
{
if(r->ch[1]==0)
r->ch[1]=p,p->parent=r;
else
insert(r->ch[1],p);
}
}
void rotate_left(node *p) //左旋
{
node *parent=p->parent,*lson=p->ch[0],*gp=p->parent->parent;
parent->ch[1]=lson;//父的右子变成左旋点的左子
if(lson) lson->parent=parent;//如果左旋点左子存在,左旋点左子的父就从左旋点变成左旋点的父
p->ch[0]=parent;//左旋点的左子变成左旋点的父
parent->parent=p;//左旋点的父,也就是变完左旋点的左子的父是左旋点
p->parent=gp;//左旋点的父变成开始左旋点的父的父
if(parent==root) {root=p; return;}//如果说开始左旋点的父是根的话,现在左旋点是根
if(gp->ch[0]==parent) gp->ch[0]=p;//如果开始左旋点的父是左旋点的父的父的左子,那么现在开始左旋点的父的父的左子变为左旋点
else gp->ch[1]=p;//反之
}
void rotate_right(node *p)// 与左旋同样的道理
{
node *parent=p->parent,*rson=p->ch[1],*gp=p->parent->parent;
parent->ch[0]=rson;
if(rson) rson->parent=parent;
p->ch[1]=parent;
parent->parent=p;
p->parent=gp;
if(parent==root) {root=p; return;}
if(gp->ch[0]==parent) gp->ch[0]=p;
else gp->ch[1]=p;
}
void treap(node *p) //判断左旋还是右旋
{
if(root == p || p->rnd >= p->parent->rnd) return;//如果已经是根,或者子的数已经比父的数要大,不需要平衡
if(p->parent->ch[0] == p) rotate_right(p);//左子右旋
else rotate_left(p);//右子左旋
treap(p);
}
void inorder(node *p)//中序打印
{
if(p->ch[0]) inorder(p->ch[0]);
printf("%d ",p->d);
if(p->ch[1]) inorder(p->ch[1]);
}
void input() //简单输入
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&pool[i].d);//输入一个数
pool[i].rnd=rand();//再随机生成一个数,做左旋右旋
}
root=&pool[1];
for(int i=2;i<=n;i++)
{
insert(root,&pool[i]);//每插入一次就平衡一次
treap(&pool[i]);
}
inorder(root);
}
int main()
{
input();
return 0;
}