pku2418水题--学写AVL


题意:给你很多单词,统计每个单词出现的频率。。。


分析:题目没什么说的。。

对AVL树,是对BST的进行了平衡处理,保证任何一棵子树深度差值不超过1.。。使得在任意情况下不会退化到O(n^2)。。。

当出现不平衡时找到最靠近插入点的左右子树相差超过1的根节点
共分四种情况:
1.左子树比右子树深超过1(只进行右旋R 或 先左旋后右旋LR)

2.右子树比左子树深超过1(只进行左旋L 或 先右旋后左旋RL)

 

 

第一次写,wa得泪流满面。。
代码:

#include<iostream>
using namespace std;

const int N=100010;
int n, cnt, num, root, taller;
char s[35];
struct node
{
	char s[36];
	int cnt, bs, lchild, rchild;
	void init()
	{
		cnt = 1;
		bs = 0;
		lchild = rchild = -1;
	}
} a[N];

void r_rotate(int &p) //右旋
{
	int lc = a[p].lchild;
	a[p].lchild = a[lc].rchild;
	a[lc].rchild = p;
	p = lc;
}
void l_rotate(int &p) //左旋
{
	int rc = a[p].rchild;
	a[p].rchild = a[rc].lchild;
	a[rc].lchild = p;
	p = rc;
}

void l_balance(int &p) //对左子树引起的不平衡进行恢复
{
	int lc, rc;
	lc = a[p].lchild;
	if(a[lc].bs==1)
	{
		a[p].bs = a[lc].bs = 0;//需在旋转前面改变。。也wa了好久
		r_rotate(p);
	}
	else
	{
		rc = a[lc].rchild;
		if(a[rc].bs==0)//初次加入该点时出现的情况。。
			a[p].bs = a[lc].bs = 0;
		else if(a[rc].bs==1)
			a[lc].bs = 0, a[p].bs = -1;
		else
			a[lc].bs = 1, a[p].bs = 0;
		a[rc].bs = 0;
		l_rotate(a[p].lchild);
		r_rotate(p);
	}
}
void r_balance(int &p)//对右子树引起的不平衡进行恢复
{
	int lc, rc;
	rc = a[p].rchild;
	if(a[rc].bs==-1)
	{
		a[p].bs = a[rc].bs = 0;
		l_rotate(p);
	}
	else
	{
		lc = a[rc].lchild;
		if(a[lc].bs==0)
			a[p].bs = a[rc].bs = 0;
		else if(a[lc].bs==1)
			a[p].bs = 0, a[rc].bs = -1;
		else
			a[p].bs = 1, a[rc].bs = 0;
		a[lc].bs = 0;
		r_rotate(a[p].rchild);
		l_rotate(p);
	}
}
void insert(int &p) //插入节点
{
	if(p==-1)
	{
		p = cnt++;
		a[p].init();
		strcpy(a[p].s, s);
		taller = 1;
		return;
	}
	int cmp=strcmp(s, a[p].s);
	if(cmp==0)
	{
		//taller = 0;//想不懂为什么非要加这一句啊。。。》添加第一个节点时taller变1了。。每次插入前将taller请0就好了。。
		a[p].cnt++;
	}
	else if(cmp<0)
	{
		insert(a[p].lchild);
		if(taller)
		{
			if(a[p].bs==1)
			{
				l_balance(p);
				taller = 0;
			}
			else
			{
				a[p].bs++;
				if(a[p].bs!=0)
					taller = 1;
				else
					taller = 0;
			}
		}
	}
	else
	{
		insert(a[p].rchild);
		if(taller)
		{
			if(a[p].bs==-1)
			{
				r_balance(p);
				taller = 0;
			}
			else
			{
				a[p].bs--;
				if(a[p].bs!=0)
					taller = 1;
				else
					taller = 0;
			}
		}
	}
}
void dfs(int p) //遍历整棵树
{
	if(p==-1)
		return;
	dfs(a[p].lchild);
	printf("%s %.4lf\n", a[p].s, (double)a[p].cnt*100/num);
	dfs(a[p].rchild);
	
}
int main()
{
	cnt = num = taller = 0;
	root = -1;
	while(gets(s))
	{
		taller = 0;
		insert(root);
		num++;
	}
	dfs(root);
	return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值