以此篇告别我琢磨AVL树模板题的2天时间(菜洗了),因为一开始写的树存在值可能相同的节点,导致我被删除节点整麻了,维护节点值不相同就好起来了TUT。
板题链接 洛谷P3369【普通平衡树】
感觉其他博客的AVL树的定义,选择,插入,删除都大差不差,我就直接上码了
首先是节点的定义
struct node{
int date;
int h;
int lsize,size; //lsize表示左子树有多少节点,size表示左子树节点数+右子树节点数+1,即以自身节点当根节点的树的大小
int cnt; //cnt表示值为date的节点有cnt个,因此该AVL树中节点的值互不相同
node* left;
node* right;
node(){ //初始化
left=NULL;
right=NULL;
h=1;
lsize=0;
size=1;
cnt=1;
}
};
接着是一些基本操作
node* creatnode(int x) //创建节点
{
node* t=new node();
t->date=x;
return t;
}
int geth(node* t) //得到该节点的高度
{
if( t==NULL )
return 0;
return t->h;
}
int getsize(node* t) //得到该节点的大小(节点数)
{
if( t==NULL )
return 0;
int tsize=t->cnt;
if( t->left!=NULL ) tsize+=t->left->size;
if( t->right!=NULL ) tsize+=t->right->size;
return tsize;
}
void updateh(node* &t) //更新函数
{
t->lsize=getsize(t->left);
t->size=getsize(t);
t->h=max(geth(t->left),geth(t->right))+1;
}
int getavl(node* t) //返回该节点的平衡因子
{
return geth(t->left)-geth(t->right);
}
接着就是维持平衡的左旋和右旋了
void L(node* &t) //左旋
{
node* temp=t->right;
t->right=temp->left;
temp->left=t;
updateh(t);
updateh(temp);
t=temp;
}
void R(node* &t) //右旋
{
node* temp=t->left;
t->left=temp->right;
temp->right=t;
updateh(t);
updateh(temp);
t=temp;
}
接下来就是操作了。
1.插入
void insert(node* &t,int x)
{
if( t==NULL ) //找到合适位置但当前节点为空,插入
{
t=creatnode(x);
return ;
}
if( x==t->date ) //树中存在值为x的节点,该节点cnt++
{
t->cnt++;
updateh(t);
}
else if( x<t->date ) //x<当前节点值,去左节点查找
{
insert(t->left,x);
updateh(t); //插入完后记得更新节点参数
if( getavl(t)==2 ) //保持平衡操作
{
if( getavl(t->left)==1 )
{
R(t); //LL
}
else
{
L(t->left); //LR
R(t);
}
}
}
else //x>当前节点值,去右节点查找
{
insert(t->right,x);
updateh(t); //插入完后记得更新节点参数
if( getavl(t)==-2 ) //保持平衡操作
{
if( getavl(t->right)==-1 ) //RR
{
L(t);
}
else
{
R(t->right); //RL
L(t);
}
}
}
}
2.找后续
int find_next(node* t,int x) //找后续,树中不一定存在x值节点
{
int ans=2147483647;
if( t==NULL )
return ans;
if( x>=t->date )
{
return find_next(t->right,x); //x大于等于当前节点,去右节点找
}
else if( x<t->date )
{
ans=t->date; //记录当前值(可能为答案)
return min(ans,find_next(t->left,x)); //去左节点继续找,因为左节点也可能大于x ,在与ans比较
}
}
3. 找前继
int find_pre(node* t,int x) //找前继,树中不一定存在x值节点
{
int ans=-2147483647;
if( t==NULL )
return ans;
if( x<=t->date )
{
return find_pre(t->left,x); //x小于等于当前节点,去右节点找
}
else if( x>t->date )
{
ans=t->date; //记录当前值(可能为答案)
return max(ans,find_pre(t->right,x)); //去右节点继续找,因为右节点也可能小于x ,在与ans比较
}
}
4. 查询x排名
int findrank(node* t,int num,int x) //找值为x节点的排名(x不一定存在) ,目前已有num个小于当前节点
{
if( t==NULL ) return num+1; //空节点,x不存在,返回排名
if( t->date==x ) //找到x
return num+t->lsize+1; //返回num+ lsize(左子树的都小于当前节点 ) +1
else if( t->date>x ) //x小于,往左节点找
{
return findrank(t->left,num,x);
}
else if( t->date<x ) //x大于,往右节点找,num加上左子树大小以及自身cnt
{
return findrank(t->right,num+t->cnt+t->lsize,x);
}
}
5. 找排名x的数
int getrank(node* t,int num,int x) //当前节点的排名范围为[ num+t->lsize+1,num+t->lsize+t->cnt ]
{
if( num+t->lsize+1<=x&&num+t->lsize+t->cnt>=x ) //x在排名范围内
{
return t->date;
}
else if( num+t->lsize>=x ) //小于排名范围,去左节点找
{
return getrank(t->left,num,x);
}
else if( num+t->lsize+t->cnt<x ) //大于排名 范围,去右节点找
{
return getrank(t->right,num+t->lsize+t->cnt,x);
}
}
6. 删除
void delet(node* &t, int x,int num)
{
if(t==NULL ) //防止RE吧。。。。
return ;
if( t->date==x ) //找到节点值为x的节点
{
if( t->cnt>num ) //如果cnt>num ,直接处理cnt
{
t->cnt-=num;
}//如果cnt==num,要用前继或者后续代替当前节点
else if( t->left!=NULL&&t->right!=NULL&&t->cnt==num ) //左右节点非空
{
if( geth(t->left)>geth(t->right) ) //左树高找前继续
{
node* temp=t->left;
while( temp->right!=NULL )
temp=temp->right;
//直接赋值
t->date=temp->date;
t->cnt=temp->cnt;
//在左节点删除temp
delet(t->left,t->date,t->cnt);
}
else //找后续续
{
node* temp=t->right;
while( temp->left!=NULL )
temp=temp->left;
t->date=temp->date;
t->cnt=temp->cnt;
//在右节点删除temp
delet(t->right,t->date,t->cnt);
}
}
else if( t->left==NULL&&t->right==NULL&&t->cnt==num ) //该节点为叶节点,直接赋空返回
{
t=NULL;
return ;
}
else //左子树或右子树为空
{
if( t->left!=NULL )
{
node* temp=t->left;
t->date=temp->date;
t->cnt=temp->cnt;
delet(t->left,t->date,t->cnt);
}
else
{
node* temp=t->right;
t->date=temp->date;
t->cnt=temp->cnt;
delet(t->right,t->date,t->cnt);
}
}
}
else if( t->date>x ) //当前节点较大,去左节点找删除
{
delet(t->left,x,num);
}
else if( t->date<x ) //当前节点较小,去右节点找删除
{
delet(t->right,x,num);
}
//删除后更新参数
updateh(t);
//如果失衡,旋转保持平衡
if( getavl(t)==2 )
{
if( getavl(t->left)==-1 )
{
L(t->left);
R(t);
}
else
{
R(t);
}
}
else if( getavl(t)==-2 )
{
if( getavl(t->right)==1 )
{
R(t->right);
L(t);
}
else
{
L(t);
}
}
updateh(t);
}
最后附上AC代码(菜b代码)
#include <bits/stdc++.h>
using namespace std;
struct node{
int date;
int h;
int lsize,rsize,size;
int cnt;
node* left;
node* right;
node(){
left=NULL;
right=NULL;
h=1;
lsize=0;
size=1;
rsize=0;
cnt=1;
}
};
node* root=NULL;
node* creatnode(int x)
{
node* t=new node();
t->date=x;
return t;
}
int geth(node* t)
{
if( t==NULL )
return 0;
return t->h;
}
int getsize(node* t)
{
if( t==NULL )
return 0;
int tsize=t->cnt;
if( t->left!=NULL ) tsize+=t->left->size;
if( t->right!=NULL ) tsize+=t->right->size;
return tsize;
//return getsize(t->left)+getsize(t->right)+1;
}
void updateh(node* &t)
{
t->lsize=getsize(t->left);
t->size=getsize(t);
t->h=max(geth(t->left),geth(t->right))+1;
}
int getavl(node* t)
{
return geth(t->left)-geth(t->right);
}
void L(node* &t)
{
node* temp=t->right;
t->right=temp->left;
temp->left=t;
updateh(t);
updateh(temp);
t=temp;
}
void R(node* &t)
{
node* temp=t->left;
t->left=temp->right;
temp->right=t;
updateh(t);
updateh(temp);
t=temp;
}
void insert(node* &t,int x)
{
if( t==NULL )
{
t=creatnode(x);
return ;
}
if( x==t->date )
{
t->cnt++;
updateh(t);
}
else if( x<t->date )
{
insert(t->left,x);
updateh(t);
if( getavl(t)==2 )
{
if( getavl(t->left)==1 )
{
R(t);
}
else
{
L(t->left);
R(t);
}
}
}
else
{
insert(t->right,x);
updateh(t);
if( getavl(t)==-2 )
{
if( getavl(t->right)==-1 )
{
L(t);
}
else
{
R(t->right);
L(t);
}
}
}
}
int find_next(node* t,int x)
{
int ans=2147483647;
if( t==NULL )
return ans;
if( x>=t->date )
{
return find_next(t->right,x);
}
else if( x<t->date )
{
ans=t->date;
return min(ans,find_next(t->left,x));
}
}
int find_pre(node* t,int x)
{
int ans=-2147483647;
if( t==NULL )
return ans;
if( x<=t->date )
{
return find_pre(t->left,x);
}
else if( x>t->date )
{
ans=t->date;
return max(ans,find_pre(t->right,x));
}
}
int findrank(node* t,int num,int x)
{
if( t==NULL ) return num+1;
if( t->date==x )
return num+t->lsize+1;
else if( t->date>x )
{
return findrank(t->left,num,x);
}
else if( t->date<x )
{
return findrank(t->right,num+t->cnt+t->lsize,x);
}
}
int getrank(node* t,int num,int x)
{
//if( x==1105 ) cout<<t->date<<" num: "<<num<<" cnt: "<<t->cnt<<endl;
if( num+t->lsize+1<=x&&num+t->lsize+t->cnt>=x )
{
return t->date;
}
else if( num+t->lsize>=x )
{
return getrank(t->left,num,x);
}
else if( num+t->lsize+t->cnt<x )
{
return getrank(t->right,num+t->lsize+t->cnt,x);
}
}
void delet(node* &t, int x,int num)
{
if(t==NULL )
return ;
if( t->date==x )
{
if( t->cnt>num )
{
t->cnt--;
}
else if( t->left!=NULL&&t->right!=NULL&&t->cnt==num )
{
if( geth(t->left)>geth(t->right) )
{
node* temp=t->left;
while( temp->right!=NULL )
temp=temp->right;
t->date=temp->date;
t->cnt=temp->cnt;
delet(t->left,t->date,t->cnt);
}
else
{
node* temp=t->right;
while( temp->left!=NULL )
temp=temp->left;
t->date=temp->date;
t->cnt=temp->cnt;
delet(t->right,t->date,t->cnt);
}
}
else if( t->left==NULL&&t->right==NULL&&t->cnt==num )
{
t=NULL;
return ;
}
else
{
if( t->left!=NULL )
{
node* temp=t->left;
t->date=temp->date;
t->cnt=temp->cnt;
delet(t->left,t->date,t->cnt);
}
else
{
node* temp=t->right;
t->date=temp->date;
t->cnt=temp->cnt;
delet(t->right,t->date,t->cnt);
}
}
}
else if( t->date>x )
{
delet(t->left,x,num);
}
else if( t->date<x )
{
delet(t->right,x,num);
}
updateh(t);
if( getavl(t)==2 )
{
if( getavl(t->left)==-1 )
{
L(t->left);
R(t);
}
else
{
R(t);
}
}
else if( getavl(t)==-2 )
{
if( getavl(t->right)==1 )
{
R(t->right);
L(t);
}
else
{
L(t);
}
}
updateh(t);
}
void print(node* t)
{
cout<<" "<<t->date;
if( t->left ) cout<<" left: "<<t->left->date;
if( t->right ) cout<<" right: "<<t->right->date;
cout<<" size: "<<t->size<<" lsize: "<<t->lsize;
cout<<" cnt: "<<t->cnt;
cout<<endl;
if( t->left ) print(t->left);
if( t->right ) print(t->right);
}
int main()
{
int q;
int op,x;
cin>>q;
while( q-- )
{
cin>>op>>x;
if( op==1 )
{
insert(root,x);
//print(root);
}
else if( op==2 )
{
delet(root,x,1);
//print(root);
}
else if( op==6 )
{
cout<<find_next(root,x)<<endl;
}
else if( op==5 )
{
cout<<find_pre(root,x)<<endl;
}
else if( op==4 )
{
cout<<getrank(root,0,x)<<endl;
}
else if( op==3 )
{
cout<<findrank(root,0,x)<<endl;
}
//cout<<" "<<root->date<<endl;
}
return 0;
}