题目如下:
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.
![](http://www.patest.cn/upload/79_mtxjq1kj3gx.jpg)
![](http://www.patest.cn/upload/79_mtxjqnwja2o.jpg)
![](http://www.patest.cn/upload/79_mtxjr4gyzdg.jpg)
![](http://www.patest.cn/upload/79_mtxjrh51o9y.jpg)
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 ythe root of the resulting AVL tree in one line.
Sample Input 1:5 88 70 61 96 120Sample Output 1:
70Sample Input 2:
7 88 70 61 96 120 90 65Sample Output 2:
88
题目要求从一棵空二叉树树开始插入不多于20个结点,在插入过程中保证二叉树为AVL树(一种自平衡二叉查找树),在最后输出AVL树的根结点。
根据概念,调平衡共有四种情况,分别是左单旋LL,右单旋RR,左右双旋LR以及右左双旋RL。
Ⅰ在讨论旋转算法之前,先用链式存储方式构建二叉树存储结点,这里除了结点处的值、左右子树地址之外,还应该有一个字段用来存储该结点的子树最大高度。
typedef struct AVLTreeNode *AVLTree;
typedef struct AVLTreeNode{
int Data;
AVLTree left;
AVLTree right;
int Height;
};
Ⅱ树高算法:
设计一个递归函数,返回值为当前结点下的子树高度
思路为如果树不空,就先递归左子树,再递归左子树,比较二者的返回值,并且返回二者较大的一个加一,如果树空就返回0。
int GetHeight(AVLTree T){
if (T){
int HL = GetHeight(T->left);
int HR = GetHeight(T->right);
int max = HL > HR ? HL : HR;
return max + 1;
}
else
return 0;
}
· Ⅲ旋转算法:
①左单旋
可以注意到,操作顺序为先让A的左子树为B的右子树,然后让B的右子树为A,注意顺序不能反。
具体实现方式为新建一个结点B并赋为A的左子树,这就把新建的结点变成了图中的B点,然后按上述操作进行赋值,最后A、B结点的树高,并且返回新的根结点。
AVLTree SingleLeftRotation(AVLTree A){
AVLTree B = A->left;
A->left = B->right;
B->right = A;
A->Height = GetMax(GetHeight(A->left), GetHeight(A->right)) + 1;
B->Height = GetMax(GetHeight(B->left), A->Height) + 1;//A is the left subtree of B
return B;
}
②右单旋
右单旋和左单旋基本一致,只需要把right和left进行对偶变换。
AVLTree SingleRightRotation(AVLTree A){
AVLTree B = A->right;
A->right = B->left;
B->left = A;
A->Height = GetMax(GetHeight(A->left), GetHeight(A->right)) + 1;
B->Height = GetMax(A->Height, GetHeight(B->right)) + 1;//A is the right subtree of B
return B;
}
③右左双旋
可以把右左双转分解为发现者下面的左单旋和左单旋结束后和发现者一起的右单旋。
AVLTree DoubleRightLeftRotation(AVLTree A){
right = SingleLeftRotation(A->right);
return SingleRightRotation(A);
}
只需要调用A右子树的左单旋,再返回A的右单旋。相当于把右左双旋反过来考虑,先后后前,从下到上。
④左右双旋
左右双旋和右左双旋同样是对偶的关系,只需要把left和right对偶变换即可。
AVLTree DoubleLeftRightRotation(AVLTree A){
A->left = SingleRightRotation(A->left);
return SingleLeftRotation(A);
}
Ⅳ插入算法
插入算法非常简单,在树空的时候新建结点,否则判断数和当前结点的大小关系,小左大右,然后判断是否高度差大于1,大于1则判断旋转类型,如果是向左插入并且数据比左子树结点还大,那么就是左旋,否则是左右双旋;对于向右插入一样,如果比右子树结点还大,那么就是 右旋,否则就是右左双旋。
注意,该插入算法的返回值是根结点。
AVLTree AVL_Insertion(int x, AVLTree T){
if (!T){
T = (AVLTree)malloc(sizeof(struct AVLTreeNode));
T->Data = x;
T->Height = 0;
T->left = T->right = NULL;
}
else if (x < T->Data){ //Insert to left
T->left = AVL_Insertion(x, T->left);
if (GetHeight(T->left) - GetHeight(T->right) == 2){
if (x < T->left->Data){
T = SingleLeftRotation(T);
}
else
{
T = DoubleLeftRightRotation(T);
}
}
}
else if (x > T->Data){ //Insert to right
T->right = AVL_Insertion(x, T->right);
if (GetHeight(T->right) - GetHeight(T->left) == 2){
if (x > T->right->Data){
T = SingleRightRotation(T);
}
else{
T = DoubleRightLeftRotation(T);
}
}
}/*if x = T->Data, not insert*/
T->Height = GetMax(GetHeight(T->left), GetHeight(T->right)) + 1;
return T;
}
完整的算法为:
#include <iostream>
using namespace std;
typedef struct AVLTreeNode *AVLTree;
typedef struct AVLTreeNode{
int Data;
AVLTree left;
AVLTree right;
int Height;
};
int GetHeight(AVLTree T){
if (T){
int HL = GetHeight(T->left);
int HR = GetHeight(T->right);
int max = HL > HR ? HL : HR;
return max + 1;
}
else
return 0;
}
int GetMax(int a, int b){
return a > b ? a : b;
}
AVLTree SingleLeftRotation(AVLTree A){
AVLTree B = A->left;
A->left = B->right;
B->right = A;
A->Height = GetMax(GetHeight(A->left), GetHeight(A->right)) + 1;
B->Height = GetMax(GetHeight(B->left), A->Height) + 1;//A is the left subtree of B
return B;
}
AVLTree SingleRightRotation(AVLTree A){
AVLTree B = A->right;
A->right = B->left;
B->left = A;
A->Height = GetMax(GetHeight(A->left), GetHeight(A->right)) + 1;
B->Height = GetMax(A->Height, GetHeight(B->right)) + 1;//A is the right subtree of B
return B;
}
AVLTree DoubleLeftRightRotation(AVLTree A){
A->left = SingleRightRotation(A->left);
return SingleLeftRotation(A);
}
AVLTree DoubleRightLeftRotation(AVLTree A){
A->right = SingleLeftRotation(A->right);
return SingleRightRotation(A);
}
AVLTree AVL_Insertion(int x, AVLTree T){
if (!T){
T = (AVLTree)malloc(sizeof(struct AVLTreeNode));
T->Data = x;
T->Height = 0;
T->left = T->right = NULL;
}
else if (x < T->Data){ //Insert to left
T->left = AVL_Insertion(x, T->left);
if (GetHeight(T->left) - GetHeight(T->right) == 2){
if (x < T->left->Data){
T = SingleLeftRotation(T);
}
else
{
T = DoubleLeftRightRotation(T);
}
}
}
else if (x > T->Data){ //Insert to right
T->right = AVL_Insertion(x, T->right);
if (GetHeight(T->right) - GetHeight(T->left) == 2){
if (x > T->right->Data){
T = SingleRightRotation(T);
}
else{
T = DoubleRightLeftRotation(T);
}
}
}/*if x = T->Data, not insert*/
T->Height = GetMax(GetHeight(T->left), GetHeight(T->right)) + 1;
return T;
}
AVLTree GetRoot(AVLTree A){
return NULL;
}
int main(){
int N;
int count = 0;
int data;
AVLTree tree = NULL;
cin >> N;
while (true){
cin >> data;
tree = AVL_Insertion(data, tree);
count++;
if (count == N) break;
}
cout << tree->Data << endl;
return 0;
}