AVL树构造代码(C++)

AVL树的构造和遍历

就是很基础的AVL树构造问题,值得注意的就是如何判断是否要进行平衡,以及进行怎么样的平衡。此处我用flag标记,标记为2或-2的结点需要平衡,flag即是左右子树高度差。如某p结点p->flag=2,即左子树高度高出右子树2,再判断p->lchild->flag值,为1的话就是LL(因为p->child的左子树也高1),为-1就是LR(p->lchild的右子树高1)。旋转的时候需要注意一点就是p结点是否是根节点,是的话,旋转后的结点要置为根节点,updata时,即重新检查二叉树有没有平衡时就需要从新的根节点开始检查了。如果不是根节点,那新的代替p的结点要与p的父节点链接。我一开始没有设定father指针,因此用了root标记位判根,后来发现旋转后父子结点的链接还是需要父亲结点的,但我懒得改代码就保留了,具体参见我代码。这里需要重视的就是结点移动过程中各节点的链接,比较复杂,不要粗心搞错了。

  • 提一点,我是自己作,想写写结点移动的代码,毕竟平时多练有好处。其实直接修改要旋转结点的data值就好了,这样就无需父节点也无需判根,方便多了。
  • AVL算是大二生觉得比较复杂的一块,我看了网上的代码感觉java偏多,然后代码比较简练,不适合新生用,所以写了一版比较详细的。如果有需要的同学看不懂得可以留言咨询我。
#include<iostream>
#include<fstream>
#include<math.h>
#include <algorithm>
#include<stdio.h>
#include<string.h>
#include <fstream>
#include<stack>
#include <map>
#include <ctime>
#include<queue>
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector<int>
#define gr greater<int>
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

struct AVL{
	AVL *lchild;
	AVL *rchild;
	AVL *father;
	int flag;
	int data;
	int root;
}; 
AVL *t = NULL, *p = NULL;
int hh, flag;

void insert(AVL *s, int x)
{
	
	if(x > s->data)
	{
		if(s->rchild != NULL)
		insert(s->rchild, x);
		else
		{
			AVL *c;
			c = new AVL; //new很重要,不如没有节点空间 
			c->data = x;
			c->lchild = c->rchild = NULL;
			c->flag = 0;
			c->root = 0;
			s->rchild = c;
			c->father = s;
		}
	}	
	else
	{
		if(s->lchild != NULL)
		insert(s->lchild, x);
		else
		{
			AVL *c;
			c = new AVL;
			c->data = x;
			c->lchild = c->rchild = NULL;
			c->flag = 0;
			s->lchild = c;
			c->father = s;
		}
	}
}

void gethigh(AVL *s, int h) //获取高度函数 
{
	if(s->lchild != NULL)
	{
		hh = max(hh, h+1);
		gethigh(s->lchild, h+1);
	} 
	if(s->rchild != NULL)
	{
		hh = max(hh, h+1);
		gethigh(s->rchild, h+1);
	}
	//cout << "insert" << endl;
}


void updata(AVL *s)
{
	hh = 1;
	if(s->lchild != NULL)
	{
		hh = 2;
		gethigh(s->lchild, 2); //结点存在,孩子结点也存在,所以至少高度为2 
		cout << "s->data = "<<s->data<<"   : the lchild is not NULL, and is " << s->lchild->data << endl;
	}
	
	int hl = hh;
	hh = 1;
	if(s->rchild != NULL)
	{
		hh = 2;
		gethigh(s->rchild, 2);
		cout << "s->data = " <<s->data<< "   : the rchild is not NULL, and is " << s->rchild->data << endl;
	}
	
	int hr = hh;
	s->flag = hl - hr;//左子树高度令为正,右子树为负,flag标记平衡常数,一旦到2就需要再平衡 
	if(s->flag == 2 || s->flag == -2)
	{
		p = s;
		cout << "p is " << p->data << "  && p->flag = " << p->flag << endl;
		flag = 1;	
	}
	//prk;
	if(s->lchild != NULL)
	updata(s->lchild);
	if(s->rchild != NULL)
	updata(s->rchild);
	
}

void change(AVL *s)
{
	cout << "p is " << p->data << "  && p->flag = " << p->flag << endl;
	//类似于链表,只要将需要改变位置的结点的前驱、后继改变即可,即这里的父子结点 
	if(p->flag == 2)
	{
		if(p->lchild->flag == 1) //LL 
		{
			AVL *r = p->lchild;
			if(r->rchild != NULL)
			p->lchild = r->rchild;
			else p->lchild = NULL;
			r->rchild = p;
			p->father = p->father;
			p->father = r;
			if(p->root == 1)
			{
				r->root = 1;
				p->root = 0;
				t = r;
			}
			else
			{
				AVL *c = r->father;
				if(c->lchild->data == p->data)
				c->lchild = r;
				else c->rchild = r;
			}
		}
		else //LR 
		{
			AVL *r = p->lchild;
			AVL *rr = r->rchild;
			if(rr->lchild != NULL)
			r->rchild = rr->lchild;
			else r->lchild = NULL;
			rr->lchild = r;
			r->father = rr;
			if(rr->rchild != NULL)
			p->lchild = rr->rchild;
			else p->lchild = NULL;
			rr->rchild = p;
			rr->father = p->father;
			p->father = r;
			if(p->root == 1)
			{
				rr->root = 1;
				p->root = 0;
				t = rr;
			}
			else
			{
				AVL *c = rr->father;
				if(c->lchild->data == p->data)
				c->lchild = rr;
				else c->rchild = rr;
			}
		}
	}
	else
	{
		if(p->rchild->flag == -1) //RR 
		{
			AVL *r = p->rchild;
			if(r->lchild != NULL)
			p->rchild = r->lchild;
			else p->rchild = NULL;
			r->lchild = p;
			r->father = p->father;
			p->father = r;
			if(p->root == 1)
			{
				r->root = 1;
				p->root = 0;
				t = r;
			}
			else
			{
				AVL *c = r->father;
				if(c->lchild->data == p->data)
				c->lchild = r;
				else c->rchild = r;
			}
		}
		else //RL 
		{
			AVL *r = p->rchild;
			AVL *rr = r->lchild;
			if(rr->rchild != NULL)
			r->lchild = rr->rchild;
			else r->lchild = NULL;
			rr->rchild = r;
			r->father = rr;
			if(rr->lchild != NULL)
			p->rchild = rr->lchild;
			else p->rchild = NULL;
			rr->lchild = p;
			rr->father = p->father;
			p->father = rr;
			if(p->root == 1)
			{
				rr->root = 1;
				p->root = 0;
				t = rr;
			}
			else
			{
				AVL *c = rr->father;
				if(c->lchild->data == p->data)
				c->lchild = rr;
				else c->rchild = rr;
			}
		}
	}
	flag = 0;
	updata(t);
	if(flag)
	change(p);
}

void pre(AVL *s)
{
	cout << s->data << " ";
	if(s->lchild != NULL)
	pre(s->lchild);
	if(s->rchild != NULL)
	pre(s->rchild);
}

void ord(AVL *s)
{
	
	if(s->lchild != NULL)
	ord(s->lchild);
	cout << s->data << " ";
	if(s->rchild != NULL)
	ord(s->rchild);
}

void bac(AVL *s) 
{
	if(s->lchild != NULL)
	bac(s->lchild);
	if(s->rchild != NULL)
	bac(s->rchild);
	cout << s->data << " ";
}

int main()
{
	int x;
	sc(x);
	t = new AVL;
	p = new AVL;
	t->data = x;
	t->lchild = NULL;
	t->rchild = NULL;
	t->flag = 0;
	t->root = 1;
	t->father = NULL;
	w(sc(x) && x!=-1)
	{
		insert(t, x); //元素插入 
		flag = 0;
		updata(t); //检测是否平衡 
		if(flag)
		{
			cout << endl << "*************" <<endl;
			change(p); //不平衡更新为AVL 
		}
		
	}
	pre(t); //前序遍历 
	prk; 
	ord(t); //中序遍历 
	prk;
	bac(t); //后序遍历 
	prk;
	return 0;
}

















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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值