PAT (Advanced Level) Practice
1066 Root of AVL Tree (25分)
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.
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
个人代码:
#include <stdio.h>
#include <algorithm>
using namespace std
;
typedef struct AVLNode
{
int height
, val
;
struct AVLNode
*lchild
, *rchild
, *parent
;
} AVLNode
, *AVLTree
;
AVLNode
*AVLTreeInsert
(AVLTree
&T
, int val
) {
if (T
== NULL) {
T
= (AVLTree
)malloc(sizeof(AVLNode
));
T
->val
= val
;
T
->lchild
= NULL;
T
->rchild
= NULL;
T
->parent
= NULL;
return T
;
} else if (val
< T
->val
) {
return AVLTreeInsert(T
->lchild
, val
);
} else {
return AVLTreeInsert(T
->rchild
, val
);
}
}
int AVLTreeHeight
(AVLTree
&T
) {
if (T
== NULL) {
return 0;
} else {
int lheight
, rheight
;
lheight
= AVLTreeHeight(T
->lchild
);
rheight
= AVLTreeHeight(T
->rchild
);
T
->height
= max(lheight
+ 1, rheight
+ 1);
return T
->height
;
}
}
void SetParent
(AVLTree
&T
) {
if (T
== NULL) {
return;
}
if (T
->lchild
!= NULL) {
T
->lchild
->parent
= T
;
SetParent(T
->lchild
);
}
if (T
->rchild
!= NULL) {
T
->rchild
->parent
= T
;
SetParent(T
->rchild
);
}
}
void AVLTreeLrevov
(AVLTree
&p
, AVLTree
&T
) {
if (p
->parent
->parent
!= NULL) {
if (p
->parent
->val
< p
->parent
->parent
->val
) {
p
->parent
->parent
->lchild
= p
;
} else {
p
->parent
->parent
->rchild
= p
;
}
}
p
->parent
->rchild
= p
->lchild
;
p
->lchild
= p
->parent
;
if (p
->lchild
->val
== T
->val
) {
T
= p
;
T
->parent
= NULL;
}
}
void AVLTreeRrevov
(AVLTree
&p
, AVLTree
&T
) {
if (p
->parent
->parent
!= NULL) {
if (p
->parent
->val
< p
->parent
->parent
->val
) {
p
->parent
->parent
->lchild
= p
;
} else {
p
->parent
->parent
->rchild
= p
;
}
}
p
->parent
->lchild
= p
->rchild
;
p
->rchild
= p
->parent
;
if (p
->rchild
->val
== T
->val
) {
T
= p
;
T
->parent
= NULL;
}
}
int main
() {
#ifdef LOCAL
freopen("./in.txt", "r", stdin);
#endif
int n
;
scanf("%d", &n
);
AVLTree T
= NULL;
AVLNode
*p
= NULL;
for (int i
= 0; i
< n
; i
++) {
int lheight
= 0, rheight
= 0, value
= 0;
int revov
= 0;
scanf("%d", &value
);
p
= AVLTreeInsert(T
, value
);
AVLTreeHeight(T
);
SetParent(T
);
while (p
!= NULL) {
if (p
->lchild
!= NULL) {
lheight
= p
->lchild
->height
;
} else {
lheight
= 0;
}
if (p
->rchild
!= NULL) {
rheight
= p
->rchild
->height
;
} else {
rheight
= 0;
}
if (abs(lheight
- rheight
) < 2) {
p
= p
->parent
;
} else break;
}
if (abs(lheight
- rheight
) >= 2) {
if (value
< p
->val
) {
p
= p
->lchild
;
if (value
< p
->val
) {
revov
= 1;
} else {
revov
= 2;
}
} else {
p
= p
->rchild
;
if (value
< p
->val
) {
revov
= 3;
} else {
revov
= 4;
}
}
}
switch (revov
) {
case 0:
break;
case 1:
AVLTreeRrevov(p
, T
);
SetParent(T
);
break;
case 2:
p
= p
->rchild
;
AVLTreeLrevov(p
, T
);
SetParent(T
);
AVLTreeRrevov(p
, T
);
SetParent(T
);
break;
case 3:
p
= p
->lchild
;
AVLTreeRrevov(p
, T
);
SetParent(T
);
AVLTreeLrevov(p
, T
);
SetParent(T
);
break;
case 4:
AVLTreeLrevov(p
, T
);
SetParent(T
);
break;
}
}
printf("%d", T
->val
);
return 0;
}
思路提示:
建立AVL树的步骤如下:
首先定义AVL树的结点,包含高度、值、指向孩子结点和双亲结点的指针等信息每读入一个结点,就要将他按照BST的排序规则插入AVL树中每个结点插入后,检查AVL树中每个结点是否满足左右子树高度相差的绝对值不超过1,方法是从刚插入的结点往上找他的双亲结点(设置双亲结点的好处)找到最近的一个不满足平衡条件的结点,根据LL、LR、RL、RR四种类型确定需要进行旋转的操作和对象注意,当树的高度和双亲节点变化后,需要及时的通过函数更新