本题考场avl树的四种旋转方法与树的深度的计算
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
首先题目告诉了四种AVL的自平衡方法,figure1到figure4分别是LL旋转,RR旋转,RL旋转与LR旋转,这是AVL树的自平衡法则
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print the root of the resulting AVL tree in one line.
Sample Input 1:
5
88 70 61 96 120
Sample Output 1:
70
Sample Input 2:
7
88 70 61 96 120 90 65
Sample Output 2:
88
思路:
在程序最开始,我们需要定义树的结构体:
typedef struct Treenode * Tree;
struct Treenode
{
int v;//储存节点的值
Tree left, right;//储存左树的位置与右树的位置
};
主程序尽量简单:
int main()
{
int n;
scanf("%d", &n);
Tree T;
T = maketree(n);//构建AVL树
printf("%d\n",T->v);//输出该树的根节点
return 0;
}
构建一颗AVL树的函数有以下几个:
Tree maketree(int n);//建立自平衡二叉树
Tree newnode(int v);//建立新节点
Tree insert(Tree T, int v);//向树中插入元素
int height(Tree T);//计算一个树的高度
Tree LLrotation(Tree T);//LL旋转,左单旋转
Tree LRrotation(Tree T);//LR旋转,左右双旋
Tree RRrotation(Tree T);//RR旋转,右单旋转
Tree RLrotation(Tree T);//RL旋转,右左双旋
其中建立树的函数时会调用两个函数:建立新节点函数与插入新元素函数,其中插入新元素的函数会调用建立新节点函数与递归调用自身,同时插入完节点后,需要根据高度函数计算该树目前是否自平衡,不平衡的话需要根据四种情况进行调整,建立树的函数如下:
Tree maketree(int n)
{
int v;
scanf("%d", &v);
Tree T = newnode(v);//建立根节点
for (int i = 1; i < n; i++)
{
scanf("%d", &v);
T = insert(T,v);//首先插入形成新的二叉树;
}
return T;
}
Tree newnode(int v)
{
Tree T = (Tree)malloc(sizeof(struct Treenode));
T->v = v;
T->left = T->right = NULL;
//T->height = 1;
return T;
}
Tree insert(Tree T, int v)
{
if (!T) T = newnode(v);
else
{
if (v < T->v )
{
T->left = insert(T->left, v);
if (height(T->left) - height(T->right) == 2)//如果插入后左边的树高度达到2
{
if (v < T->left->v)//LL旋转
T = LLrotation(T);
else//LR旋转
T = LRrotation(T);
}
}
else
{
T->right = insert(T->right, v);
if (height(T->right) - height(T->left) == 2)//如果插入后右边的树高度达到2
{
if (v < T->right->v)//RL旋转
T = RLrotation(T);
else//RR旋转
T = RRrotation(T);
}
}
}
return T;
}
int height(Tree T)
{
int hl, hr, max;
if (T)
{
hl = height(T->left);
hr = height(T->right);
max = hl > hr ? hl : hr;
return max + 1;
}
else
return 1;
}
根据题目的提示,我们需要对四种旋转的方式定义四个函数
LL旋转:
方法如上,代码如下:
Tree LLrotation(Tree T)
{
Tree a = T, b = T->left;//记录原来根节点,根节点的左节点
Tree bl=b->left, br=b->right, ar=a->right;//记录三个需要旋转的树
a->left = br;
a->right = ar;
b->left = bl;
b->right = a;
return b;
}
LR旋转:
方法如上,代码如下:
Tree LRrotation(Tree T)
{
Tree a = T, b = T->left,c = b->right;//记录原来根节点,根节点的左节点,左节点的右节点
Tree bl = b->left, cl = c->left, cr=c->right,ar = a->right;//记录四个需要旋转的树
b->left = bl;
b->right = cl;
a->left = cr;
a->right = ar;
c->left = b;
c->right = a;
return c;
}
RR旋转:
方法如上,代码如下:
Tree RRrotation(Tree T)
{
Tree a = T, b = T->right;//记录原来根节点,根节点的右节点
Tree al = a->left, bl = b->left, br = b->right;//记录三个需要旋转的树
a->left = al;
a->right = bl;
b->left = a;
b->right = br;
return b;
}
RL旋转:
方法如上,代码如下:
Tree RLrotation(Tree T)
{
Tree a = T, b = T->right, c = b->left;//记录原来根节点,根节点的右节点,右节点的左节点
Tree al=a->left,br=b->right,cl=c->left,cr=c->right;//记录四个需要旋转的树
a->left = al;
a->right = cl;
b->left = cr;
b->right = br;
c->left = a;
c->right = b;
return c;
}
以上就完成了一个AVL树的建立
源代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct Treenode * Tree;
struct Treenode
{
int v;//储存节点的值
Tree left, right;//储存左树的位置与右树的位置
};
Tree maketree(int n);//建立自平衡二叉树
Tree newnode(int v);//建立新节点
Tree insert(Tree T, int v);//向树中插入元素
int height(Tree T);//计算一个树的高度
Tree LLrotation(Tree T);//LL旋转,左单旋转
Tree LRrotation(Tree T);//LR旋转,左右双旋
Tree RRrotation(Tree T);//RR旋转,右单旋转
Tree RLrotation(Tree T);//RL旋转,右左双旋
int main()
{
int n;
scanf("%d", &n);
Tree T;
T = maketree(n);//构建AVL树
printf("%d\n",T->v);//输出该树的根节点
return 0;
}
Tree maketree(int n)
{
int v;
scanf("%d", &v);
Tree T = newnode(v);//建立根节点
for (int i = 1; i < n; i++)
{
scanf("%d", &v);
T = insert(T,v);//首先插入形成新的二叉树;
}
return T;
}
Tree newnode(int v)
{
Tree T = (Tree)malloc(sizeof(struct Treenode));
T->v = v;
T->left = T->right = NULL;
//T->height = 1;
return T;
}
Tree insert(Tree T, int v)
{
if (!T) T = newnode(v);
else
{
if (v < T->v )
{
T->left = insert(T->left, v);
if (height(T->left) - height(T->right) == 2)//如果插入后左边的树高度达到2
{
if (v < T->left->v)//LL旋转
T = LLrotation(T);
else//LR旋转
T = LRrotation(T);
}
}
else
{
T->right = insert(T->right, v);
if (height(T->right) - height(T->left) == 2)//如果插入后右边的树高度达到2
{
if (v < T->right->v)//RL旋转
T = RLrotation(T);
else//RR旋转
T = RRrotation(T);
}
}
}
return T;
}
int height(Tree T)
{
int hl, hr, max;
if (T)
{
hl = height(T->left);
hr = height(T->right);
max = hl > hr ? hl : hr;
return max + 1;
}
else
return 1;
}
Tree LLrotation(Tree T)
{
Tree a = T, b = T->left;//记录原来根节点,根节点的左节点
Tree bl=b->left, br=b->right, ar=a->right;//记录三个需要旋转的树
a->left = br;
a->right = ar;
b->left = bl;
b->right = a;
return b;
}
Tree LRrotation(Tree T)
{
Tree a = T, b = T->left,c = b->right;//记录原来根节点,根节点的左节点,左节点的右节点
Tree bl = b->left, cl = c->left, cr=c->right,ar = a->right;//记录四个需要旋转的树
b->left = bl;
b->right = cl;
a->left = cr;
a->right = ar;
c->left = b;
c->right = a;
return c;
}
Tree RRrotation(Tree T)
{
Tree a = T, b = T->right;//记录原来根节点,根节点的右节点
Tree al = a->left, bl = b->left, br = b->right;//记录三个需要旋转的树
a->left = al;
a->right = bl;
b->left = a;
b->right = br;
return b;
}
Tree RLrotation(Tree T)
{
Tree a = T, b = T->right, c = b->left;//记录原来根节点,根节点的右节点,右节点的左节点
Tree al=a->left,br=b->right,cl=c->left,cr=c->right;//记录四个需要旋转的树
a->left = al;
a->right = cl;
b->left = cr;
b->right = br;
c->left = a;
c->right = b;
return c;
}