AVL树的操作——郁闷的出纳员,平衡树解法

今天学习了一下AVL,顺便用AVL树 A掉了这道经典的题,以前用树状数组解过这个题,今天记录一下AVL的解法。如有错误之处欢迎指正,各位大牛不要笑话我。

该题需要用平衡树:定义这样的一颗平衡树,根节点大于等于左儿子节点,小于右儿子节点。(也可以规范的定义左儿子小于根,小于右儿子,但是要加入新的数据域)

为了球第K小,除了原本的height域以外加入一个size域,表示以当前节点为跟的子树有多少个节点。

操作1:数据域的维护

首先要在旋转前维护该节点的子树的height和size,然后才能根据更新的数据,判断该树是否平衡,然后旋转

void fix(node* &R)

{

	R->h = max(R->rchild->h,R->lchild->h) + 1;

	R->size = R->rchild->size + R->lchild->size + 1;

}

该函数维护了平衡树的数据域

操作2:旋转化操作

插入和删除的时候用同样的旋转维护该树

	void rightsinglerotate(node* &R)//LL型旋转,单旋一次

	{

		node * lc = R->lchild;

		R->lchild = lc->rchild;

                fix(R);

		lc->rchild = R;

		R = lc;

                fix(R);

	}



	void leftsinglerotate(node* &R)//RR型旋转,单选一次

	{

		node * rc = R->rchild;

		R->rchild = rc->lchild;

		fix(R);

		rc->lchild = R;

		R = rc;

		fix(R);

	}



	void leftdoublerotate(node* &R)//RL型旋转,双旋

	{

		rightsinglerotate(R->rchild);

		leftsinglerotate(R);

	}



	void rightdoublerotate(node* &R)//LR型旋转,双旋

	{

		leftsinglerotate(R->lchild);

		rightsinglerotate(R);

	}



	void maintain(node* &R)

	{

		if(R->lchild != MYNULL)

		{

			if(R->lchild->lchild->h == R->rchild->h + 1)

				rightsinglerotate(R);

			else if(R->lchild->rchild->h == R->rchild->h + 1)

				rightdoublerotate(R);

		}

		if(R->rchild != MYNULL)

		{

 			if(R->rchild->rchild->h == R->lchild->h + 1)

				leftsinglerotate(R);

			else if(R->rchild->lchild->h == R->lchild->h + 1)

				leftdoublerotate(R);

		}

	}

        

操作3:求第K小的操作,也就是size域的用途

int findK(node* &R,int k)

{

	if(k == R->lchild->size + 1)

		return R->value;

	else if(k <= R->lchild->size)

		return findK(R->lchild,k);

	else if(k > R->size - R->rchild->size)

		return findK(R->rchild,k + R->rchild->size - R->size);

}

有了size域后就可以方便的实现该功能了,函数代码简单非常好理解比较好理解

操作4:erase函数,要完成该题的统计功能,看erase了多少次

	void erase(node* &R,T value)

	{

		if(R == MYNULL)

			return;

		if(R->value == value)

		{

			if(R->rchild == MYNULL)

			{

				node * tmp = R;

				R = tmp->lchild;

			}

			else

			{

				node *tmp = R->rchild;

				while(tmp->lchild != MYNULL)

					tmp = tmp->lchild;

				R->value = tmp->value;

				erase(R->rchild,tmp->value);

				fix(R);

			}

                        return;

		}

		else if(value < R->value)

			erase(R->lchild,value);

		else if(value < R->value)

			erase(R->rchild,value);

		fix(R);

                maintain(R);

	}

思想就是找到,该节点后,如果该节点R没有右儿子,直接删除,把他的左子树R->child接到他的父节点即可。如果有右儿子,那就找到他右子树中最小的元素的节点tmp,把他放到当前节点R->value = tmp->value。再以他的右子树为根递归的删除tmp->value;递归完右子树维护数据域。

最后在调整树使其不失衡。

有了这些操作就可以轻松的完成题目的要求了,

完整的代码如下

/*

 * =====================================================================================

 *

 *       Filename:  AVLtree.cpp

 *

 *    Description:  AVLtree with template

 *

 *        Version:  1.0

 *        Created:  2010年12月27日 09时45分44秒

 *       Revision:  none

 *       Compiler:  gcc

 *

 *         Author:  ronaflx

 *        Company:  hit-acm-group

 *

 * =====================================================================================

 */



#include <iostream>

#include <cstring>

#include <cstdio>

using namespace std;

int delta;

const int INF = 10000000;

template<typename T>

class AVL

{

public:

	AVL()

	{

		pp = pool;

                TMP = node(0,0,NULL,NULL);

                MYNULL = &TMP;

		roof = MYNULL;

	}

	void insert(T k)

	{

		insert(roof,k);

	}



	void erase(T k)

	{

		erase(roof,k);

	}



	bool empty()

	{

		return roof == MYNULL;

	}

	int findK(int k)

	{

		if(k <= 0)

			return -INF;

                return findK(roof,k);

	}

	struct node

	{

		node *lchild,*rchild;

		T value;

		int h,size;

		node(){}

		node (int h,int size,node * lchild,node *rchild)

		{

			this->size = size;

			this->h = h;

			this->lchild = lchild;

			this->rchild = rchild;

		}

	};

	node* roof;

private:

#define max(a,b) ((a) < (b) ? (b) : (a))



	static const int N = 1000000;

	node* MYNULL,TMP;

	//为了快速方便的求高度而设立的虚空节点



	node pool[N],*pp;

	int findK(node* &R,int k)

	{

		if(k == R->lchild->size + 1)

			return R->value;

		else if(k <= R->lchild->size)

			return findK(R->lchild,k);

		else if(k > R->size - R->rchild->size)

			return findK(R->rchild,k + R->rchild->size - R->size);

	}

        

	void fix(node* &R)

	{

		R->h = max(R->rchild->h,R->lchild->h) + 1;

		R->size = R->rchild->size + R->lchild->size + 1;

	}

        

	void rightsinglerotate(node* &R)//LL型旋转,单旋一次

	{

		node * lc = R->lchild;

		R->lchild = lc->rchild;

                fix(R);

		lc->rchild = R;

		R = lc;

                fix(R);

	}



	void leftsinglerotate(node* &R)//RR型旋转,单选一次

	{

		node * rc = R->rchild;

		R->rchild = rc->lchild;

		fix(R);

		rc->lchild = R;

		R = rc;

		fix(R);

	}



	void leftdoublerotate(node* &R)//RL型旋转,双旋

	{

		rightsinglerotate(R->rchild);

		leftsinglerotate(R);

	}



	void rightdoublerotate(node* &R)//LR型旋转,双旋

	{

		leftsinglerotate(R->lchild);

		rightsinglerotate(R);

	}



	void maintain(node* &R)

	{

		if(R->lchild != MYNULL)

		{

			if(R->lchild->lchild->h == R->rchild->h + 1)

				rightsinglerotate(R);

			else if(R->lchild->rchild->h == R->rchild->h + 1)

				rightdoublerotate(R);

		}

		if(R->rchild != MYNULL)

		{

 			if(R->rchild->rchild->h == R->lchild->h + 1)

				leftsinglerotate(R);

			else if(R->rchild->lchild->h == R->lchild->h + 1)

				leftdoublerotate(R);

		}

	}

        

	void insert(node* &R,T value)

	{

		if(R == MYNULL)

                {

                        R = mynew(value);

                        return;

                }

		else if(value <= R->value)

			insert(R->lchild,value);

		else if(value > R->value)

			insert(R->rchild,value);

                fix(R);

                maintain(R);

	}

	void erase(node* &R,T value)

	{

		if(R == MYNULL)

			return;

		if(R->value == value)

		{

			if(R->rchild == MYNULL)

			{

				node * tmp = R;

				R = tmp->lchild;

			}

			else

			{

				node *tmp = R->rchild;

				while(tmp->lchild != MYNULL)

					tmp = tmp->lchild;

				R->value = tmp->value;

				erase(R->rchild,tmp->value);

				fix(R);

			}

                        return;

		}

		else if(value < R->value)

			erase(R->lchild,value);

		else if(value < R->value)

			erase(R->rchild,value);

		fix(R);

                maintain(R);

	}



	node* mynew(T value)

	{

		pp->lchild = pp->rchild = MYNULL;

                pp->size = pp->h = 1;

		pp->value = value;

		return pp++;

	}

#undef max

};

AVL<int> avltree;

int main()

{

	int n,minn;

	char cmd;

	int f,cnt = 0;

	while(scanf("%d %d",&n,&minn) == 2)

	{

		delta = 0;

		cnt = 0;

		while(!avltree.empty())

		{

			avltree.erase(avltree.roof->value);

		}

		for(int i = 0;i < n;i++)

		{

			scanf(" %c %d",&cmd,&f);

			if(cmd == 'I')

                        {

                                if(f < minn)

                                    continue;

				avltree.insert(f - delta);

                        }

			else if(cmd == 'A')

				delta += f;

			else if(cmd == 'F')

                        {

                                int tmp = avltree.findK(avltree.roof->size - f + 1);

                                if(tmp == -INF)

                                        printf("-1\n");

                                else

                                        printf("%d\n",tmp + delta);

                        }

			else if(cmd == 	'S')

			{

				delta -= f;

				while(!avltree.empty())

				{

					int tmp = avltree.findK(1);

                                        tmp += delta;

					if(tmp >= minn)

						break;

					else

                                        {

						cnt++;

                                                avltree.erase(tmp - delta);

                                        }

				}

			}

		}

		printf("%d\n",cnt);

	}

	return 0;

}



你可能感兴趣的:(操作)