AVL是一种自平衡的二叉查找树。
不同于普通的二叉查找树之处在于:每个节点的左右子树高度差最多为1,故每个节点多了一个高度(height)属性。
其实现难点在于插入和删除时要检测节点高度差是否满足上述条件,当超过1时,分四种情况进行调节。
case1:左儿子的左子树插入值 left-left
case2:左儿子的右子树插入值 left-right
case3:右儿子的左子树插入值 right-left
case4:右儿子的右子树插入值 right-right
以上四种情况中,虽然删除操作不是“插入值”,但是删除后导致的结果可以转换成插入来看待处理。
为了简便说明原理,此处仅对删除操作的一种类型作图说明。
以下,删除的值在左侧时,即remove函数中treeNode->val > data的情况。
#include <queue>
#include <iostream>
using namespace std;
struct AVLTreeNode
{
int val;
int height;
AVLTreeNode *left;
AVLTreeNode *right;
};
int GetHeight(AVLTreeNode *treeNode)
{
//must update this height when insert or move a node
return treeNode == NULL ? -1 : treeNode->height;
//if use the code below,there is no need to use member "height"
//and there is no need to update height anymore
//but it may cost much time as it uses recursion to get the height every time
/*if(treeNode == NULL)
return -1;
return 1 + max(GetHeight(treeNode->left), GetHeight(treeNode->right));*/
}
//case 1,add "1" to 3,2(left-left)
/*
3 2
2 -> 1 3
1
*/
void RotateWithLeftChild(AVLTreeNode *&treeNode)
{
AVLTreeNode *p = treeNode->left;
treeNode->left = p->right;
p->right = treeNode;
treeNode->height = max(GetHeight(treeNode->left), GetHeight(treeNode->right)) + 1;
p->height = max(GetHeight(p->left), treeNode->height) + 1;
treeNode = p;
}
//case 4,add "3" to 1,2(right-right)
/*
1 2
2 -> 1 3
3
*/
void RotateWithRightChild(AVLTreeNode *&treeNode)
{
AVLTreeNode *p = treeNode->right;
treeNode->right = p->left;
p->left = treeNode;
treeNode->height = max(GetHeight(treeNode->left), GetHeight(treeNode->right)) + 1;
p->height = max(GetHeight(p->right), treeNode->height) + 1;
treeNode = p;
}
//case 2,add "2" to 3,1(left-right)
/*
3 3 2
1 -> 2 -> 1 3
2 1
*/
void DoubleWithLeftChild(AVLTreeNode *&treeNode)
{
RotateWithRightChild(treeNode->left);
RotateWithLeftChild(treeNode);
}
//case 3,add "2" to 1,3(right-left)
/*
1 1 2
3 -> 2 -> 1 3
2 3
*/
void DoubleWithRightChild(AVLTreeNode *&treeNode)
{
RotateWithLeftChild(treeNode->right);
RotateWithRightChild(treeNode);
}
AVLTreeNode *FindMin(AVLTreeNode *treeNode)
{
if(treeNode == NULL)
return NULL;
else if(treeNode->left == NULL)
return treeNode;
else
return FindMin(treeNode->left);
}
AVLTreeNode *FindMax(AVLTreeNode *treeNode)
{
if (treeNode == NULL)
return NULL;
else if (treeNode->right == NULL)
return treeNode;
else
return FindMax(treeNode->right);
}
void Insert(AVLTreeNode *&treeNode, int data)
{
if(treeNode == NULL){
treeNode = new AVLTreeNode;
treeNode->left = NULL;
treeNode->right = NULL;
treeNode->val = data;
}
else if (treeNode->val > data) {//go to left subtree
Insert(treeNode->left,data);
if (GetHeight(treeNode->left) - GetHeight(treeNode->right) == 2){
if(data < treeNode->left->val) //left-left
RotateWithLeftChild(treeNode);
else //left-right
DoubleWithLeftChild(treeNode);
}
} else if (treeNode->val < data){ //go to right subtree
Insert(treeNode->right,data);
if(GetHeight(treeNode->right) - GetHeight(treeNode->left) == 2){
if (data > treeNode->right->val)
RotateWithRightChild(treeNode);
else
DoubleWithRightChild(treeNode);
}
} else ;//duplicate, do nothing
//it's impossible that treeNode is NULL here
//so update it's height is safe
treeNode->height = max(GetHeight(treeNode->left),GetHeight(treeNode->right)) + 1;
}
void Remove(AVLTreeNode *&treeNode, int data)
{
if(treeNode == NULL)//not found
return;
if (treeNode->val > data) //go to left subtree
{
Remove(treeNode->left,data);
if (GetHeight(treeNode->right) - GetHeight(treeNode->left) == 2)
{
if(treeNode->right->right != NULL)
RotateWithRightChild(treeNode);
else
DoubleWithRightChild(treeNode);
}
}
else if (treeNode->val < data) //go to right subtree
{
Remove(treeNode->right,data);
if (GetHeight(treeNode->left) - GetHeight(treeNode->right) == 2)
{
if (treeNode->left->left != NULL)
RotateWithLeftChild(treeNode);
else
DoubleWithLeftChild(treeNode);
}
}
else if(treeNode->left != NULL && treeNode->right != NULL)//found,has two children
{
treeNode->val = FindMin(treeNode->right)->val;
Remove(treeNode->right,treeNode->val);//not "data"!!
if (GetHeight(treeNode->left) - GetHeight(treeNode->right) == 2)
{
if(treeNode->left->left != NULL)
RotateWithLeftChild(treeNode);
else
DoubleWithLeftChild(treeNode);
}
}
else // found,has one or no child
{
AVLTreeNode *tmp = treeNode;
treeNode = (treeNode->left != NULL) ? treeNode->left : treeNode->right;
delete tmp;
tmp = NULL;
}
//if treeNode is NULL,treeNode->height will cause error
//so if treeNode is a leaf, there is no need to update its height
if(treeNode != NULL)
treeNode->height = max(GetHeight(treeNode->left), GetHeight(treeNode->right)) + 1;
}
void LevelOrderTraverse(AVLTreeNode *root)
{
if(root == NULL) return;
queue<AVLTreeNode*> Q;
Q.push(root);
while(!Q.empty())
{
AVLTreeNode *p = Q.front();
if (p->left != NULL)
Q.push(p->left);
if (p->right != NULL)
Q.push(p->right);
cout << p->val <<"("<<p->height<<") ";
Q.pop();
}
cout << "\n";
}
void PreOrderTraverse(AVLTreeNode *treeNode)
{
if (treeNode != NULL)
{
cout << treeNode->val <<"("<<treeNode->height<<") ";
PreOrderTraverse(treeNode->left);
PreOrderTraverse(treeNode->right);
}
}
void InOrderTraverse(AVLTreeNode *treeNode)
{
if (treeNode != NULL)
{
InOrderTraverse(treeNode->left);
cout << treeNode->val <<"("<<treeNode->height<<") ";
InOrderTraverse(treeNode->right);
}
}
void PostOrderTraverse(AVLTreeNode *treeNode)
{
if (treeNode != NULL)
{
PostOrderTraverse(treeNode->left);
PostOrderTraverse(treeNode->right);
cout << treeNode->val <<"("<<treeNode->height<<") ";
}
}
void MakeEmpty(AVLTreeNode *&treeNode)
{
if (treeNode != NULL)
{
MakeEmpty(treeNode->left);
MakeEmpty(treeNode->right);
delete treeNode;
}
treeNode = NULL;
}
void BuildAVLTree(AVLTreeNode *&root,int a[], int n)
{
for (int i = 0; i < n; i++)
{
Insert(root,a[i]);
}
}
int main(void)
{
int a[] = {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};//test insert
int b[] = {2,1,3,4};//test remove
AVLTreeNode *root = NULL;
//BuildAVLTree(root,a,sizeof(a)/sizeof(a[0]));
BuildAVLTree(root,b,sizeof(b)/sizeof(b[0]));
LevelOrderTraverse(root);
Remove(root,4);
PreOrderTraverse(root);
cout << "\n";
InOrderTraverse(root);
cout << "\n";
MakeEmpty(root);
return 0;
}