c++的AVL树(洛谷--普通平衡树)

以此篇告别我琢磨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;
}

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值