AVL搜索树是二叉排序数的一个改进,在AVL中任何两个儿子子树的高度差不超过1,故查找、删除、插入在平均和最坏情况下都是O(logn)。
代码如下:
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cstdio>
#include<cmath>
using namespace std;
typedef struct AVLTree{
int nData,nHeight;
struct AVLTree* pLeft;
struct AVLTree* pRight;
}AVLTree;
int max(int a,int b);
int Height(AVLTree* pNode);
AVLTree* Insert(int nData,AVLTree *pNode);
AVLTree* LLRotate(AVLTree* pNode);
AVLTree* RRRotate(AVLTree* pNode);
AVLTree* LRRotate(AVLTree* pNode);
AVLTree* RLRotate(AVLTree* pNode);
void DeleteTree(AVLTree** ppRoot);
void PrintTree(AVLTree* pRoot);
int main()
{
int i,x;
AVLTree* pRoot = NULL;
srand((unsigned int)time(NULL));
for (i = 0; i < 20; i++){
x = rand() % 100;
cout<<x<<' ';
pRoot = Insert(x,pRoot);
}
cout<<endl;
PrintTree(pRoot);
DeleteTree(&pRoot);
return 0;
}
int max(int a,int b)
{
return (a>b?a:b);
}
int Height(AVLTree* pNode)
{
if (pNode == NULL) return -1;
return pNode -> nHeight;
}
AVLTree* Insert(int nData,AVLTree *pNode)
{
if (pNode == NULL){
pNode = (AVLTree* )malloc(sizeof(AVLTree));
pNode->nData = nData;
pNode->nHeight = 0;
pNode->pLeft = pNode->pRight = NULL;
} else if ( nData < pNode->nData )//插入到左子树中去
{
pNode -> pLeft = Insert(nData, pNode -> pLeft);
if ( Height(pNode -> pLeft) - Height(pNode -> pRight) == 2)
{
if (nData < pNode -> pLeft -> nData){
pNode = LLRotate(pNode);//LL型旋转
} else pNode = LRRotate(pNode);//LR型旋转
}
} else if ( nData > pNode -> nData)//插入到右子树中去
{
pNode -> pRight = Insert(nData, pNode -> pRight);
if ( Height(pNode -> pRight) - Height(pNode -> pLeft) == 2)
{
if (nData < pNode -> pRight -> nData){
pNode = RLRotate(pNode);//RL型旋转
} else pNode = RRRotate(pNode);//RR型旋转
}
}
pNode -> nHeight = max(Height(pNode -> pLeft),Height(pNode -> pRight)) + 1;
return pNode;
}
AVLTree* LLRotate(AVLTree* pNode)
{
AVLTree* p1;
p1 = pNode -> pLeft;
pNode -> pLeft = p1 -> pRight;
p1 -> pRight = pNode;
pNode -> nHeight = max(Height(pNode -> pLeft),Height(pNode -> pRight)) + 1;
p1 -> nHeight = max(Height(p1 -> pLeft),pNode -> nHeight) + 1;
return p1;
}
AVLTree* RRRotate(AVLTree* pNode)
{
AVLTree* p1;
p1 = pNode -> pRight;
pNode -> pRight = p1 -> pLeft;
p1 -> pLeft = pNode;
pNode -> nHeight = max(Height(pNode -> pLeft),Height(pNode -> pRight)) + 1;
p1 -> nHeight = max(Height(p1 -> pRight),pNode -> nHeight) + 1;
return p1;
}
AVLTree* LRRotate(AVLTree* pNode)
{
pNode -> pLeft = RRRotate(pNode -> pLeft);
return LLRotate(pNode);
}
AVLTree* RLRotate(AVLTree* pNode)
{
pNode -> pRight = LLRotate(pNode -> pRight);
return RRRotate(pNode);
}
void DeleteTree(AVLTree** ppRoot)
{
if ( ppRoot == NULL || *ppRoot == NULL)
return ;
DeleteTree(&((*ppRoot) -> pLeft));
DeleteTree(&((*ppRoot) -> pRight));
free( *ppRoot);
*ppRoot = NULL;
}
void PrintTree(AVLTree* pRoot)
{
if (pRoot == NULL ) return;
static int n = 0;
PrintTree(pRoot -> pLeft);
printf("[%d]nData = %d %d\n",++n,pRoot -> nData, pRoot -> nHeight);
PrintTree(pRoot -> pRight);
}
这里只写了插入操作,查询操作比较简单,删除和插入也很相似,不过要考虑删除当前节点后,用该节点的哪个儿子来代替自己的位置。
插入操作时会出现当前搜索树不再是AVL搜索树的情况,这时需要对树进行维护,有4种情况LL型、LR型、RR型、RL型,学AVL搜索树主要要把这四种情况的维护了解,基本就学会了。
在整个代码过程中,要记得更新节点的高度,方便后续操作。
具体可以看下维基百科:https://zh.wikipedia.org/wiki/AVL%E6%A0%91
例题:poj2418 Hardwood Species
可以用AVL树练习一下,也可以用其它方法做,代码会在其它blog上贴出