源码地址:http://download.csdn.net/detail/mcu_tian/9555855
AVL平衡二叉树是一种特殊的查找树,是一种每个节点的左右子树深度不超过1。
AVL是绝对平衡树,增删的操作复杂度过高,应用不如红黑树。
AVL树的引入,就是为了解决二叉查找树的不平衡性导致时间复杂度大大下降。
那么AVL就保持住了(BST)的最好时间复杂度O(logn),所以每次的插入和删除都要确保二叉树的平衡。
在对AVL平衡树的插入和删除操作的过程中,有可能会破坏AVL树的特性,此时就要通过旋转操作将插入节点的树恢复为AVL树。
struct AvlNode
{
ElementType element;
struct AvlNode *left;
struct AvlNode *right;
int frequency;
int heigh;
};
typedef struct AvlNode *NodePtr;
typedef struct AvlNode *AvlTree;
typedef struct AvlNode Node;
就插入操作而言
AvlTree SingleRotateLeft(AvlTree t)//左单旋转
{
NodePtr tmp = t->left;
t->left = tmp->right;
tmp->right = t;
t->heigh = MAX(Heigh(t->left),Heigh(t->right))+1;//更新子树节点深度
tmp->heigh = MAX(Heigh(tmp->left),Heigh(tmp->right))+1;
return tmp;
}
AvlTree SingleRotateRight(AvlTree t)
{
NodePtr tmp = t->right;
t->right = tmp->left;
tmp->left = t;
t->heigh = MAX(Heigh(t->left),Heigh(t->right))+1;
tmp->heigh = MAX(Heigh(tmp->left),Heigh(tmp->right))+1;
return tmp;
}
第三种情况:
该种情况,单旋转的操作不能实现新平衡,先对左子树进行右旋转,旋转之后,然后再进行左旋转
右-左双旋转的操作C语言实现
AvlTree DoubleRotateLeft(AvlTree t)
{
t->left = SingleRotateRight(t->left);//先右再左
t = SingleRotateLeft(t);
return t;
}
该种情况,单旋转的操作不能实现新平衡,先对右子树进行左旋转,旋转之后,然后再进行右旋转
左-右双旋转的操作C语言实现
AvlTree doubleRotateRight(AvlTree t)
{
t->right = SingleRotateLeft(t->right);//先左再右
t = SingleRotateRight(t);
return t;
}
在搞定旋转实现新平衡之后,那就实现了AVL插入、删除操作的最最关键部分
插入操作Insert
插入操作的实现用递归的方法C语言实现:
AvlTree Insert(ElementType element, AvlTree t)
{
if(t == NULL)
{
t = MallocAvlNode(element); //节点插入位置
if(t == NULL)
{
printf("malloc avl node failed\n");
return t;
}
}
else if(element < t->element)
{
t->left = Insert(element,t->left); //插入元素小于节点元素则插入左子树中
if(Heigh(t->left) - Heigh(t->right) == 2)
{
if(element < t->left->element) //为第一种情况
{
t = SingleRotateLeft(t);
}
else
{
t= DoubleRotateLeft(t);//第三种情况
}
}
}
else if(element > t->element) //若是大于则插入右子树
{
t->right = Insert(element,t->right);
if(Heigh(t->right) - Heigh(t->left) >= 2)
{
if(element > t->element) //第二种情况
{
t = SingleRotateRight(t);
}
else
{
t = doubleRotateRight(t);//第四种情况
}
}
}
else //若是相等,更行节点结构中frequency,进行加1
{
++t->frequency;
}
t->heigh = MAX(Heigh(t->left),Heigh(t->right))+1; //更新节点的heigh成员
return t;
}
删除操作中:
AVL节点的删除跟查找树思路是一样的,参考:http://blog.csdn.net/mcu_tian/article/details/51668883
删除节点之后,检查AVL的平衡性,若是AVL平衡性遭到破坏,则要建立新的平衡,进行旋转操作,与insert类似,但是判断时那种不平衡的情况不同。
测试
测试代码如下:
AvlTree t = NULL;
int main(void)
{
int a[20] = {30,22,15,233,45,64,23,674,43,46,13,76,71,74,654,63,41,66,2,155};//测试数组
int i;
for(i = 0;i < 20;++i)
{
t = Insert(a[i],t);
}
PrintAvlTreeInorder(t);//中序打印AVL树,若是插入成功,则会从小到大的顺序依次打印插入的节点
return 0;
}
测试结果如下,符合预期: