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;
}