今天来细说下 AVL 树,并结合图示代码来认识并掌握 AVL 树的创建,删除,体会下 AVL 特有的自平衡性。
目录:
AVL 概念
AVL 的旋转
AVL 树旋转实现
AVL 树代码实现(C语言)
测试实例
AVL 概念
AVL 也是二叉树的一种,所以符合所有二叉树应有的特性,以及遍历方法
与二叉树不同的是,AVL树是一颗平衡树:
节点 root,左子节点的高度 与 右子节点的高度,最大差值 = 1
下面看看 AVL 树的示例:
理论上来讲 root 节点深度 = 1,依次增加,这里相反是因为后续代码初始节点深度 = 1
再来看看 非 AVL 树的示例,把上图的节点 6 去掉
可见针对 节点 5 来讲,左子树深度=3, 右子树深度=1,已经超过最大深度 1,所以不是 AVL 树
AVL 树的旋转
我们在操作树一定发生:添加或者删除节点,AVL 的状态可能会被破坏,基于不同形态的 非 AVL 树,我们有以下 四种姿态 需要通过旋转重回 AVL 形态
如果把AVL树(平衡树)看做一个人,左右子节点就是左右手提的东西
左手重或者右手重就会失去平衡,失去平衡的原因就是姿态
比如:LR,左子节点深度过大,且是因为左子节点下的右子节点(多余)造成的
形态一:LL 树 (Left-Left)
节点 6 的左右不平衡,原因是
1. Left 节点 4 更重
2. 造成节点 4 更重的原因是 4 的 Left 节点 3 还有子节点
形态二:RR 树 (Right-Right)
节点 3 的左右不平衡,原因是
1. Right 节点 6 更重
2. 造成节点 6 更重的原因是 8 的 Right 节点 8 还有子节点
形态三:LR 树 (Left-Right)
节点 8 的左右不平衡,原因是
1. Left 节点 4 更重
2. 造成节点 4 更重的原因是 4 的 Right 节点 5 还有子节点
形态四:RL 树 (Right-Left)
节点 3 的左右不平衡,原因是
1. Right 节点 8 更重
2. 造成节点 8 更重的原因是 8 的 Left 节点 5 还有子节点
AVL 树旋转实现
形态一:LL 树旋转
既然左手 K1 重了,那么左手 K1 就当脑袋,脑壳 K2 顺势变成右手,这样占用了 新脑袋的右手,原本 K1 的右手就只能丢给 K2 的左手
/* LL Rotation AVL Tree
** Parameters:
** root - avl tree
**
k2 k1
k1 c -LL-> a k2
a b d b c
d
*/
PNode ll_rotation(PNode k2)
{
PNode k1;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->deep = MAX( DEEP(k2->left), DEEP(k2->right) ) + 1;
k1->deep = MAX( DEEP(k1->left), k2->deep ) + 1;
return k1;
}
形态二:RR 树旋转
既然右手 K2 重了,那么右手 K2 就当脑袋,脑壳 K1 顺势变成左手,这样占用了 新脑袋的左手,原本 K2 的左手就只能丢给 K1 的右手
/* RR Rotation AVL Tree
** Parameters:
** root - avl tree
**
k1 k2
a k2 -RR-> k1 c
b c a b d
d
*/
PNode rr_rotation(PNode k1)
{
PNode k2;
k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1->deep = MAX( DEEP(k1->left), DEEP(k1->right) ) + 1;
k2->deep = MAX( DEEP(k2->right), k1->deep ) + 1;
return k2;
}
形态三:LR 树旋转
需经过两次变化,RR + LL ,按照右到左(LR)名字
/* LR Rotation AVL Tree
** Parameters:
** root - avl tree
**
k3 k3 k2
k1 d --RR-> k2 d --LL-> k1 k3
a k2 k1 c a b c d
b c a b
*/
PNode lr_rotation(PNode k3)
{
PNode k1, k2;
k1 = k3->left;
k2 = rr_rotation(k1);
k3->left = k2;
k2 = ll_rotation(k3);
return k2;
}
形态四:RL 树旋转
需经过两次变化,LL+RR ,按照右到左(RL)名字
/* LR Rotation AVL Tree
** Parameters:
** root - avl tree
**
k3 k3 k2
k1 d --RR-> k2 d --LL-> k1 k3
a k2 k1 c a b c d
b c a b
*/
PNode lr_rotation(PNode k3)
{
PNode k1, k2;
k1 = k3->left;
k2 = rr_rotation(k1);
k3->left = k2;
k2 = ll_rotation(k3);
return k2;
}
AVL 树代码实现
有个限定:
1. 左子节点值 < root 节点值 < 右子节点值
2. 不存在相同节点值
数据结构
typedef struct AVLTreeNode{
int val;
int deep;
struct AVLTreeNode *left;
struct AVLTreeNode *right;
}Node, *PNode;
获取树深
#define DEEP(node) ( node == NULL ? 0 : node->deep )
/* Get AVL Tree's Deep
** Parameters:
** root - avl tree
** Note: Deep incream from leaf(1) to root
**
*/
int avltree_get_deep(PNode root)
{
return DEEP(root);
}
获取树的最小值的节点
/* Get AVL Tree's Minimum Val Node
** Parameters:
** root - avl tree
*/
PNode avltree_get_min(PNode root)
{
if(root == NULL)
return NULL;
while(root->left)
root = root->left;
return root;
}
获取树的最大值的节点
/* Get AVL Tree's Minimum Val Node
** Parameters:
** root - avl tree
*/
PNode avltree_get_min(PNode root)
{
if(root == NULL)
return NULL;
while(root->left)
root = root->left;
return root;
}
创建树的节点
/* Create AVL Tree Node
** Parameters:
** val - val
** left - left child
** right - right child
*/
PNode avltree_create_node(int val, PNode left, PNode right)
{
PNode newNode = (PNode)malloc(sizeof(Node));
if(newNode == NULL)
return NULL;
newNode->val = val;
newNode->deep = 1;
newNode->left = left;
newNode->right = right;
return newNode;
}
查找树的节点
/* Search Node of AVL Tree
** Parameters:
** root - avl tree
** val - node's val
*/
PNode avltree_search_node(PNode root, int val)
{
if(root == NULL || root->val == val)
return root;
if(val < root->val)
return avltree_search_node(root->left, val);
else
return avltree_search_node(root->right, val);
}
插入节点到树,如果没有根节点则创建根节点
/* Insert New Node to AVL Tree
** Parameters:
** root - avl tree
** val - node to insert
*/
PNode avltree_insert_node(PNode root, int val)
{
if(root == NULL)
{
root = avltree_create_node(val, NULL, NULL);
if(root == NULL)
return NULL;
}
else if(val < root->val)
{
root->left = avltree_insert_node(root->left, val);
if( ( DEEP(root->left) - DEEP(root->right) ) == 2 )
{
if(val < root->left->val)
{
printf("do ll...val=%d\n", val);
root = ll_rotation(root);
}
else
{
printf("do lr...val=%d\n", val);
root = lr_rotation(root);
}
}
}
else if(val > root->val)
{
root->right = avltree_insert_node(root->right, val);
if( ( DEEP(root->right) - DEEP(root->left) ) == 2 )
{
if(val > root->right->val)
{
printf("do rr...val=%d\n", val);
root = rr_rotation(root);
}
else
{
printf("do rl...val=%d\n", val);
root = rl_rotation(root);
}
}
}
else
printf("insert %d fails, val exsits.\n", val);
root->deep = MAX( DEEP(root->left), DEEP(root->right) ) + 1;
return root;
}
删除指定值得节点
/* Delete Node of AVL Tree
** Parameters:
** root - avl tree
** val - node's val
*/
PNode avltree_delete_node_by_val(PNode root, int val)
{
PNode node;
node = avltree_search_node(root, val);
if(node)
{
printf("find node, val=%d\n", node->val);
avltree_delete_node(root, node);
}
else
printf("not find val:%d\n", val);
return root;
}
删除指定节点
/* Delete Node of AVL Tree
** Parameters:
** root - avl tree
** node - node to delete
*/
PNode avltree_delete_node(PNode root, PNode node)
{
if(root == NULL || node == NULL)
return NULL;
if(node->val < root->val) // left side
{
root->left = avltree_delete_node(root->left, node);
if(DEEP(root->right) - DEEP(root->left) == 2)
{
PNode r = root->right;
if(DEEP(r->left) > DEEP(r->right))
root = rl_rotation(root);
else
root = rr_rotation(root);
}
}
else if(node->val > root->val) // right side
{
root->right = avltree_delete_node(root->right, node);
if(DEEP(root->left) - DEEP(root->right) == 2)
{
PNode l = root->left;
if(DEEP(l->left) > DEEP(l->right))
root = ll_rotation(root);
else
root = lr_rotation(root);
}
}
else // find
{
if(root->left && root->right)
{
if(DEEP(root->left) > DEEP(root->right))
{
// 1. find max node in left side
// 2. set max node val to root
// 3. delete max node
PNode maxNode = avltree_get_max(root->left);
root->val = maxNode->val;
root->left = avltree_delete_node(root->left, maxNode);
}
else
{
// 1. find min node in right side
// 2. set min node val to root
// 3. delete min node
PNode minNode = avltree_get_min(root->right);
root->val = minNode->val;
root->right = avltree_delete_node(root->right, minNode);
}
}
else
{
PNode tmp = root;
root = root->left ? root->left : root->right;
free(tmp);
}
}
return root;
}
销毁树
/* Destory AVL Tree
** Parameters:
** root - avl tree
*/
void avltree_destory(PNode root)
{
if(root == NULL)
return;
if(root->left)
avltree_destory(root->left);
if(root->right)
avltree_destory(root->right);
printf("free %d\n", root->val);
free(root);
}
测试实例
int main(void)
{
int i;
int len;
int nodes[] ={3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
len = sizeof(nodes) / sizeof(nodes[0]);
PNode root = NULL;
for(i=0; i<len; i++)
{
root = avltree_insert_node(root, nodes[i]);
}
printf("\npreorder:\n");
preorder(root);
printf("\ninorder:\n");
inorder(root);
printf("\npreorder:\n");
postorder(root);
printf("\nroot's deep: %d\n", DEEP(root));
printf("\nminimum: %d\n", avltree_get_min(root)->val);
printf("\nmaxmum: %d\n", avltree_get_max(root)->val);
printf("-----------delete node start-------\n");
avltree_delete_node_by_val(root, 12);
printf("\npreorder:\n");
preorder(root);
printf("\n");
avltree_delete_node_by_val(root, 2);
printf("\npreorder:\n");
preorder(root);
printf("\n");
printf("-----------delete node end-------\n");
printf("\ndesotry avl tree\n");
avltree_destory(root);
return 0;
}
构建完成的树:
执行结果:
do ll...val=1
do rr...val=5
do rr...val=6
do rr...val=7
do rl...val=15
do rl...val=14
do rr...val=13
do ll...val=12
do ll...val=11
do ll...val=10
do lr...val=9
preorder:
val=7, deep=5
val=4, deep=3
val=2, deep=2
val=1, deep=1
val=3, deep=1
val=6, deep=2
val=5, deep=1
val=13, deep=4
val=11, deep=3
val=9, deep=2
val=8, deep=1
val=10, deep=1
val=12, deep=1
val=15, deep=2
val=14, deep=1
val=16, deep=1
inorder:
val=1, deep=1
val=2, deep=2
val=3, deep=1
val=4, deep=3
val=5, deep=1
val=6, deep=2
val=7, deep=5
val=8, deep=1
val=9, deep=2
val=10, deep=1
val=11, deep=3
val=12, deep=1
val=13, deep=4
val=14, deep=1
val=15, deep=2
val=16, deep=1
preorder:
val=1, deep=1
val=3, deep=1
val=2, deep=2
val=5, deep=1
val=6, deep=2
val=4, deep=3
val=8, deep=1
val=10, deep=1
val=9, deep=2
val=12, deep=1
val=11, deep=3
val=14, deep=1
val=16, deep=1
val=15, deep=2
val=13, deep=4
val=7, deep=5
root's deep: 5
minimum: 1
maxmum: 16
-----------delete node start-------
find node, val=12
preorder:
val=7, deep=5
val=4, deep=3
val=2, deep=2
val=1, deep=1
val=3, deep=1
val=6, deep=2
val=5, deep=1
val=13, deep=4
val=10, deep=3
val=9, deep=2
val=8, deep=1
val=11, deep=1
val=15, deep=2
val=14, deep=1
val=16, deep=1
find node, val=2
preorder:
val=7, deep=5
val=4, deep=3
val=3, deep=2
val=1, deep=1
val=6, deep=2
val=5, deep=1
val=13, deep=4
val=10, deep=3
val=9, deep=2
val=8, deep=1
val=11, deep=1
val=15, deep=2
val=14, deep=1
val=16, deep=1
-----------delete node end-------
desotry avl tree
free 1
free 3
free 5
free 6
free 4
free 8
free 9
free 11
free 10
free 14
free 16
free 15
free 13
free 7
小结
总算是描述完成(其实还没有,依据示例进行构建的过程留给用心的朋友自行画图,看看结果是否符合预期,这样才能加深 AVL 几种姿态的转变的理解),对照代码和图示应该对 AVL 树有了新的认识
早期在工作项目中有看到基于 AVL 树的实现,当时一头雾水,现在是时候重温了