关闭

AVL树学习笔记&模板

标签: 平衡树
297人阅读 评论(0) 收藏 举报
分类:

AVL树是一种平衡二叉查找树,利用高度严格维护树的平衡,因此,即便是在最坏的情况下各项操作的时间复杂度都是O(logN),相比splay的优点是常数小,但是功能没有splay那么强大。平衡二叉树(Balanced Binary Tree):由阿德尔森一维尔斯和兰迪斯(Adelson-Velskii and Landis)于1962年首先提出的,所以又称为AVL树。

如果T是一棵非空的二叉搜索树,TL和TR分别是其左子树和右子树,那么当T满足以下条件时,T是一棵AVL树:
1)TL和TR 是AVL树;
2)|hL-hR|≤1,hL和hR分别是左子树和右子树的高度


对于一个不平衡的节点的定义:它的左右子树的高度差为2。

当插入一个节点后,树可能不平衡,我们把不平衡的那个节点叫做a。

现在有四种情况:

1.对a的左儿子的左子树进行了一次插入
2.对a的左儿子的右子树进行了一次插入
3.对a的右儿子的左子树进行了一次插入
4.对a的右儿子的右子树进行了一次插入

由于1,4和2,3是镜像对称的,我们只需要考虑第1,2种情况。我们把这种调节不平衡的方法叫做“旋转”。

zig右旋(right_rotate)(实用于第一种情况),在左子树D上插入新节点使其高度增1,导致节点A的平衡因子增到 2,造成了不平衡。为使树恢复平衡,从A沿插入路径连续取3个节点A、B和D,它们处于一条方向为“/”的直线上,需要做LL旋转。以节点B为旋转轴,将节点A顺时针旋转成为B的右孩子,B代替原来A的位置,原来B的右孩子E转为A的左孩子。


类似的,我们把它的对称叫做zag左旋(left_rotate,谐音记忆"这个是右旋,那个是左旋")

zagzig双旋(实用于第二种情况),在子树F或G中插入新节点,该子树的高度增1。节点A的平衡因子变为 2,发生了不平衡。首先以节点E为旋转轴,将节点B逆时针旋转,以E代替原来B的位置,做zag旋转。再以节点E为旋转轴,将节点A顺时针旋转,做zig旋转,使之平衡化。



根据对称,对于第三种情况就是zigzag双旋。

旋转代码:

int right_rotate(int r)//zig右旋
{
	int t = tree[r].lc;
	tree[r].lc = tree[t].rc;
	tree[t].rc = r;
	tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
	tree[t].h = Max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;
	return t;
}
int left_rotate(int r)//zag左旋
{
	int t = tree[r].rc;
	tree[r].rc = tree[t].lc;
	tree[t].lc = r;
	tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
	tree[t].h = Max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;
	return t;
}
int right_left_rotate(int r)//zigzag双旋
{
	tree[r].rc = right_rotate(tree[r].rc);
	return left_rotate(r);
}
int left_right_rotate(int r)//zagzig双旋
{
	tree[r].lc = left_rotate(tree[r].lc);
	return right_rotate(r);
}

插入代码:

void maintain(int &r)
{
	if(tree[tree[r].lc].h == tree[tree[r].rc].h+2)//左子树高了
	{
		int t = tree[r].lc;
		if(tree[tree[t].lc].h == tree[tree[r].rc].h+1) r = right_rotate(r);//左子树的左儿子,对应第一种情况
		else if(tree[tree[t].rc].h == tree[tree[r].rc].h+1) r = left_right_rotate(r);	
	}
	else if(tree[tree[r].rc].h == tree[tree[r].lc].h+2)//右子树高了
	{
		int t = tree[r].rc;
		if(tree[tree[t].rc].h == tree[tree[r].lc].h+1) r = left_rotate(r);//右子树的右儿子,对应第四种情况
		else if(tree[tree[t].lc].h == tree[tree[r].lc].h+1) r = right_left_rotate(r);
	}
	tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;//高度更新
}
int insert(int r,int x)
{
	if(r == 0)//找到一个空的节点,赋值
	{
		tree[++pos].h = 1;//高度初始化
		tree[pos].v = x;
		return pos;
	}
	if(x < tree[r].v) tree[r].lc = insert(tree[r].lc,x);//插入的数小于根节点,因此在它的左子树插入
	else if(x > tree[r].v) tree[r].rc = insert(tree[r].rc,x);
	maintain(r);//维持节点r的平衡
	return r;//返回新的根节点
}

当插入的节点有重复的时候,需要再开一个cnt域,如果tree[r].v==x,那么cnt++,否则还是像原来一样的插入

删除节点的时候就比较麻烦了。

如果需要删掉的那个节点是叶子节点或者只有左儿子或者只有右儿子,那么直接删掉;否则从左子树中去一个最大的节点来替代它。

int delt(int &r,int x)
{
    int tx;
    if(x == tree[r].v||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
    {
        if(tree[r].lc == 0||tree[r].rc == 0)
        {
            tx = tree[r].v;
            r = tree[r].lc+tree[r].rc;
            return tx;
        }
        else tree[r].v = delt(tree[r].lc,x);//用左子树的最大值来替换
    }
    else
    {
        if(x < tree[r].v) tx = delt(tree[r].lc,x);
        else tx = delt(tree[r].rc,x);
    }
    maintain(r);//调整根节点
    return tx;//返回最大值
}


如果我们要求第k大值或者第k小值,那么还要在树中维护一个size域,保存以它为根节点的子树的节点个数。

int kth(int r,int k)//查找第k大,tree[r].tot保存了值等于tree[r].v的个数
{
	if(k >= tree[tree[r].rc].sz+1&&k <= tree[tree[r].rc].sz+tree[r].tot) return tree[r].v;//找到
	if(k < tree[tree[r].rc].sz+1) return kth(tree[r].rc,k);//在右子树中
	else return kth(tree[r].lc,k-tree[tree[r].rc].sz-tree[r].tot);//在左子树中,此种情况下,K值发生变化,因为要求得的那个点它在左子树中的排名发生了变化
}

求前驱后继:

void prem(int x,int r)//x的前驱
{
    if(r == 0) return;
    if(tree[r].v < x)
    {
        x1 = tree[r].v;
        prem(x,tree[r].rc);
    }
    else prem(x,tree[r].lc);
}
void nexm(int x,int r)//后继
{
    if(r == 0) return;
    if(tree[r].v > x)
    {
        x2 = tree[r].v;
        nexm(x,tree[r].lc);
    }
    else nexm(x,tree[r].rc);
}

附NOI2004,,郁闷的出纳员,特别注意另开一个delta表示工资的变化量

#include<cstdio>
#include<iostream>
#define pii pair<int,int>
using namespace std;
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Abs(int x) {return x>0?x:-x;}
struct AVL
{
	int lc,rc,v,sz,h,tot;
}tree[100010];
int pos,n,minn,x,delta,root,now_worker,hire_worker;
char ops[3];
int right_rotate(int r)
{
	int t = tree[r].lc;
	tree[r].lc = tree[t].rc;
	tree[t].rc = r;
	tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
	tree[t].h = Max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;
	tree[r].sz = tree[tree[r].lc].sz+tree[tree[r].rc].sz+tree[r].tot;
	tree[t].sz = tree[tree[t].lc].sz+tree[tree[t].rc].sz+tree[t].tot;
	return t;
}
int left_rotate(int r)
{
	int t = tree[r].rc;
	tree[r].rc = tree[t].lc;
	tree[t].lc = r;
	tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
	tree[t].h = Max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;
	tree[r].sz = tree[tree[r].lc].sz+tree[tree[r].rc].sz+tree[r].tot;
	tree[t].sz = tree[tree[t].lc].sz+tree[tree[t].rc].sz+tree[t].tot;
	return t;
}
int right_left_rotate(int r)
{
	tree[r].rc = right_rotate(tree[r].rc);
	return left_rotate(r);
}
int left_right_rotate(int r)
{
	tree[r].lc = left_rotate(tree[r].lc);
	return right_rotate(r);
}
void maintain(int &r)
{
	if(tree[tree[r].lc].h == tree[tree[r].rc].h+2)
	{
		int t = tree[r].lc;
		if(tree[tree[t].lc].h == tree[tree[r].rc].h+1) r = right_rotate(r);
		else if(tree[tree[t].rc].h == tree[tree[r].rc].h+1) r = left_right_rotate(r);	
	}
	else if(tree[tree[r].rc].h == tree[tree[r].lc].h+2)
	{
		int t = tree[r].rc;
		if(tree[tree[t].rc].h == tree[tree[r].lc].h+1) r = left_rotate(r);
		else if(tree[tree[t].lc].h == tree[tree[r].lc].h+1) r = right_left_rotate(r);
	}
	tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
	tree[r].sz = tree[tree[r].lc].sz+tree[tree[r].rc].sz+tree[r].tot;
}
int insert(int r,int x)
{
	if(r == 0)
	{
		tree[++pos].sz = 1;
		tree[pos].h = 1;
		tree[pos].v = x;
		tree[pos].tot = 1;
		return pos;
	}
	if(x < tree[r].v) tree[r].lc = insert(tree[r].lc,x);
	else if(x > tree[r].v) tree[r].rc = insert(tree[r].rc,x);
	else tree[r].sz++,tree[r].tot++;
	maintain(r);
	return r;
}
int kth(int r,int k)
{
	if(k >= tree[tree[r].rc].sz+1&&k <= tree[tree[r].rc].sz+tree[r].tot) return tree[r].v;
	if(k < tree[tree[r].rc].sz+1) return kth(tree[r].rc,k);
	else return kth(tree[r].lc,k-tree[tree[r].rc].sz-tree[r].tot);
}
int least_money(int r)
{
	int res = 0x3f3f3f3f;
	while(r)
	{
		res = tree[r].v;
		r = tree[r].lc;
	}
	return res;
}
pii del(int &r,int x)
{
	int Tv,Ttot;
	pii t;
	if(x == tree[r].v||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
	{
		if(tree[r].lc == 0||tree[r].rc == 0)
		{
			Tv = tree[r].v,Ttot = tree[r].tot;
			r = tree[r].lc+tree[r].rc;
			return make_pair(Tv,Ttot);
		}
		else
		{
			t = del(tree[r].lc,x);
			tree[r].v = t.first;
			tree[r].tot = t.second;
		}
	}
	else 
	{
		if(x<tree[r].v) t = del(tree[r].lc,x);
		else t = del(tree[r].rc,x);
	}
	maintain(r);
	return t;
}
int main()
{
	scanf("%d%d",&n,&minn);
	while(n--)
	{
		scanf("%s%d",ops,&x);
		if(ops[0] == 'I'&&x >= minn) root = insert(root,x-delta),now_worker++;
		else if(ops[0] == 'A') delta += x;
		else if(ops[0] == 'S')
		{
			int tx;
			pii t;
			delta -= x;
			while((tx=least_money(root))+delta < minn)
			{
				t = del(root,tx);
				now_worker -= t.second;
				hire_worker += t.second;
			}
		}
		else if(ops[0] == 'F')
		{
			if(now_worker >= x) printf("%d\n",kth(root,x)+delta);
			else printf("-1\n");
		}
	}
	printf("%d\n",hire_worker);
}

附HNOI2004,宠物收养所,剩余的要么全是人要么全是动物,所以不用开两棵树

#include<cstdio>
#define MAXN 80010
#define mod 1000000
using namespace std;
inline int Max(int a,int b)
{return a>b?a:b;}
inline int Abs(int x)
{return x>0?x:-x;}
inline int Min(int a,int b)
{return a<b?a:b;}
struct AVL
{
    int lc,rc,h,v;
}tree[MAXN];
int n,xx,root,x1,x2,pos;
bool flag;
int right_rotate(int r)
{
    int t = tree[r].lc;
    tree[r].lc = tree[t].rc;
    tree[t].rc = r;
    tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
    tree[t].h = Max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;
    return t;
}
int left_rotate(int r)
{
    int t = tree[r].rc;
    tree[r].rc = tree[t].lc;
    tree[t].lc = r;
    tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
    tree[t].h = Max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;
    return t;
}
int left_right_rotate(int r)
{
    tree[r].lc = left_rotate(tree[r].lc);
    return right_rotate(r);
}
int right_left_rotate(int r)
{
    tree[r].rc = right_rotate(tree[r].rc);
    return left_rotate(r);
}
int insert(int r)
{
    if(r == 0)
    {
        tree[++pos].h = 1;
        tree[pos].v = xx;
        return pos;
    }
    if(xx<tree[r].v)
    {
        tree[r].lc = insert(tree[r].lc);
        if(tree[tree[r].lc].h == tree[tree[r].rc].h+2)
        {
            if(xx<tree[tree[r].lc].v) r = right_rotate(r);
            else if(xx>tree[tree[r].lc].v) r = left_right_rotate(r); 
        }
    }
    else if(xx>tree[r].v)
    {
        tree[r].rc = insert(tree[r].rc);
        if(tree[tree[r].rc].h == tree[tree[r].lc].h+2)
        {
            if(xx>tree[tree[r].rc].v) r = left_rotate(r);
            else if(xx<tree[tree[r].lc].v) r = right_left_rotate(r);
        }
    }
    tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
    return r;
}
void prem(int x,int r)
{
    if(r == 0) return;
    if(tree[r].v < x)
    {
        x1 = tree[r].v;
        prem(x,tree[r].rc);
    }
    else prem(x,tree[r].lc);
}
void nexm(int x,int r)
{
    if(r == 0) return;
    if(tree[r].v > x)
    {
        x2 = tree[r].v;
        nexm(x,tree[r].lc);
    }
    else nexm(x,tree[r].rc);
}
void adjust(int &r)
{
    if(tree[tree[r].lc].h == tree[tree[r].rc].h+2)
    {
        int t = tree[r].lc;
        if(tree[tree[t].lc].h == tree[tree[r].rc].h+1) r = right_rotate(r);
        else if(tree[tree[t].rc].h == tree[tree[r].rc].h+1)
        {
            tree[r].lc = left_rotate(tree[r].lc);
            r = right_rotate(r);
        }
    }
    else if(tree[tree[r].rc].h == tree[tree[r].lc].h+2)
    {
        int t = tree[r].rc;
        if(tree[tree[t].rc].h == tree[tree[r].lc].h+1) r = left_rotate(r);
        else if(tree[tree[t].lc].h == tree[tree[r].lc].h+1)
        {
            tree[r].rc = right_rotate(tree[r].rc);
            r = left_rotate(r);
        }
    }
    tree[r].h = Max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
}
int delt(int &r,int x)
{
    int tx;
    if(x == tree[r].v||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
    {
        if(tree[r].lc == 0||tree[r].rc == 0)
        {
            tx = tree[r].v;
            r = tree[r].lc+tree[r].rc;
            return tx;
        }
        else tree[r].v = delt(tree[r].lc,x);
    }
    else
    {
        if(x < tree[r].v) tx = delt(tree[r].lc,x);
        else tx = delt(tree[r].rc,x);
    }
    adjust(r);
    return tx;
}
int main()
{
    int cnt0 = 0,a,ans = 0;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d",&a,&xx);
        if(a)
        {
            if(cnt0 > 0)
            {
                x1 = x2 = 0;
                prem(xx,root);
                nexm(xx,root);
                if(x1 == 0) x1 = x2;
                else if(x2&&xx-x1>x2-xx) x1 = x2;
                ans += Abs(x1-xx)%mod;
                if(ans >= mod) ans -= mod;
                delt(root,x1);
            }
            else root = insert(root);
            cnt0--;
        }
        else
        {
            if(cnt0 < 0)
            {
                x1 = x2 = 0;
                prem(xx,root);
                nexm(xx,root);
                if(x1 == 0) x1 = x2;
                else if(x2&&xx-x1>x2-xx) x1 = x2;
                ans += Abs(x1-xx)%mod;
                if(ans >= mod) ans -= mod;
                delt(root,x1);
            }
            else root = insert(root);
            cnt0++;
        }
    }
    printf("%d\n",ans);
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:37614次
    • 积分:1541
    • 等级:
    • 排名:千里之外
    • 原创:121篇
    • 转载:2篇
    • 译文:0篇
    • 评论:4条
    最新评论