您的位置:首页 > 理论基础 > 数据结构算法

AVL树的插入、删除、查找操作

2017-01-18 14:53 381 查看
AVL树是一种带有平衡条件的二叉查找树,所有节点都是基于平衡的。所谓平衡,即某个节点的左右子树的高度差最多相差1。空树的高度定义为-1。

下面我们通过如下两棵树(图片来自《数据结构与算法分析–C语言描述》)进一步了解怎样的树才是AVL树。



上图只有左边的树才是AVL树,那么下面我们来分析一下左边的树

(某个节点的高 = MAX(子树的高, 右子树的高 )+ 1)

节点3的高为0

节点4的高为1

节点1的高为0

节点7的高为0

节点2的高为2

节点8的高为1

节点5的高为3

你可以看到任一节点的左右子树的差都没有超过2,那么我们再看看右边的树

节点2的高为2

节点8的高为0

所以对于节点7来说,左右子树的高度差相差为2 > 1,失去平衡。

下面我们接着来说AVL的插入、删除、查找操作。

插入和删除操作都有可能导致AVL树的不平衡(为什么呢?原来的树是平衡的,即某个节点的左右子树的高度差小于2,假设左子树的高为1,右子树的高为0,如果这个时候,在这个节点的左子树插入一个节点,那么该节点的左右子树的高度差就为2了,删除操作也是一样的)。

对于出现不平衡的时候,需要通过旋转来解决。下面我们直接来看看插入操作。

插入操作

插入节点==》有可能失去平衡==》通过旋转操作来使树达到平衡

我们把需要重新平衡的节点叫做A,那么出现不平衡的情况,会有下面四种

1. 对A节点的左儿子的左子树进行插入

2. 对A节点的左儿子的右子树进行插入

3. 对A节点的右儿子的左子树进行插入

4. 对A节点的右儿子的右子树进行插入

下图对应上面四种情况



针对情况一和情况四,我们采取的是单旋转(旋转一次)的操作

针对情况二和情况三,我们采取的是双旋转(旋转两次)的操作

单旋转,其法则是,如果哪边偏高,就往另一边旋转,

如情况一,旋转后的效果如下图



情况四旋转后的效果如下图



下图(来自《数据结构与算法分析–C语言描述》)对应情况一,从图中可以看出,K2的左右节点的高度差为2,不平衡,左边偏高,所以要往右边旋转。



我们直接来看看该单旋转算法的实现

Position * avl_tree_single_rotate_with_left(AVL_TREE * k2)
{
Position * k1;

k1 = k2->lChild;
k2->lChild = k1->rChild;
k1->rChild = k2;

k2->height = avl_tree_max(avl_tree_height(k2->lChild), avl_tree_height(k2->rChild)) + 1;
k1->height = avl_tree_max(avl_tree_height(k1->lChild), avl_tree_height(k1->rChild)) + 1;

return k1;
}


双旋转,先旋转失去平衡节点K3的第一个儿子节点K1,然后再旋转K3。如情况二,旋转后的最终效果如下图



情况三,旋转后的最终效果如下图



下图(来自《数据结构与算法分析–C语言描述》)对应情况二,从图上可以看出,K3节点的左右子树高度差为2,不平衡,需要先旋转K1和K2,然后再旋转K2和K3。



我们来看看该双旋转算法的实现

Position * avl_tree_double_rotate_with_left(AVL_TREE * k3)
{
/* Rotate between k1 and k2 */
k3->lChild = avl_tree_single_rotate_with_right(k3->lChild);

/* Rotate between k2 and k3 */
return avl_tree_single_rotate_with_left(k3);
}


删除操作

删除操作可以参考二叉查找树的删除操作,其实就是分以下三种情况

1. 如果删除的value比tree->value大,那么继续往右边搜索

2. 如果删除的value比tree->value小,那么继续往左边搜索

3. 如果找到删除的value,那么又要分以下两种情况处理

1. 如果该节点有左右孩子的,那么用右子树的最小节点替代这个被删除的节点,然后再递归删除右子树的最小节点

2. 如果该节点只有一个左或者右孩子或者是没有孩子节点的,直接删除,返回相应的tree指针

删除操作,也是有可能造成树的不平衡。比如,删除下面这棵树的节点4,就会引起节点3的不平衡(左孩子的高为2,右孩子的高为0)



有一个很重要的一点,删除之前,树是平衡的,所以删除之后,不管删除节点有几个孩子,其左右子节点的高度差最多是2,不会超过2(删除节点的父节点或者是父父节点,再往上也是一样的),否则原来的树就是不平衡的,删除之后,无非有可能出现下面这四种情况









当删除之后,先要更新tree的高度,然后再判断tree是否失去平衡,如果失去平衡,再按照下面的算法调整

/* Update the height of tree */
tree->height = avl_tree_max(avl_tree_height(tree->lChild), avl_tree_height(tree->rChild)) + 1;

if(avl_tree_height(tree->lChild) - avl_tree_height(tree->rChild) == 2)
{
if(tree->lChild->rChild)
tree = avl_tree_double_rotate_with_left(tree);
else
tree = avl_tree_single_rotate_with_left(tree);
}
else if(avl_tree_height(tree->rChild)- avl_tree_height(tree->lChild) == 2)
{
if(tree->rChild->lChild)
tree = avl_tree_double_rotate_with_right(tree);
else
tree = avl_tree_single_rotate_with_right(tree);
}


查找操作

这个最简单,主要有三种情况:

1. 当查找value比tree->value小的时候,继续往左边查找

2. 当查找value比tree->value大的时候,继续往右边查找

3. 当查找value == tree->value时,返回

下面是上述操作的实现代码(下面代码有用到tree_visual_create.h,该头文件是将二叉树可视化,方便查看结果,具体可以参考二叉树的可视化

avl_tree.h

#ifndef __AVL_TREE_H__
#define __AVL_TREE_H__

typedef int ElementType;

typedef struct AVL_TREE_T
{
ElementType value;
struct AVL_TREE_T * lChild;
struct AVL_TREE_T * rChild;
int height;
}AVL_TREE;

typedef AVL_TREE Node;
typedef AVL_TREE Position;

extern void avl_tree_main(void);

#endif


avl_tree.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "avl_tree.h"
#include "tree_visual_create.h"

int avl_tree_max(int h1, int h2)
{
if(h1 > h2)
return h1;
else
return h2;
}

int avl_tree_height(AVL_TREE * tree)
{
if(NULL == tree)
return -1;
else
return tree->height;
}

Node * avl_tree_find(AVL_TREE * tree, ElementType value)
{
Node * node = NULL;

if(tree)
{
if(tree->value == value)
node = tree;
else if(tree->value > value)
node = avl_tree_find(tree->lChild, value);
else if(tree->value < value)
node = avl_tree_find(tree->rChild, value);
}

return node;
}

Node * avl_tree_find_min(AVL_TREE * tree)
{
AVL_TREE * node = NULL;

if(tree)
{
if(tree->lChild)
node = avl_tree_find_min(tree->lChild);
else
node = tree;
}

return node;
}

Node * avl_tree_find_max(AVL_TREE * tree)
{
AVL_TREE * node = NULL;

if(tree)
{
if(tree->rChild)
node = avl_tree_find_max(tree->rChild);
else
node = tree;
}

return node;
}

Position * avl_tree_single_rotate_with_left(AVL_TREE * k2) { Position * k1; k1 = k2->lChild; k2->lChild = k1->rChild; k1->rChild = k2; k2->height = avl_tree_max(avl_tree_height(k2->lChild), avl_tree_height(k2->rChild)) + 1; k1->height = avl_tree_max(avl_tree_height(k1->lChild), avl_tree_height(k1->rChild)) + 1; return k1; }

Position * avl_tree_single_rotate_with_right(AVL_TREE * k1)
{
Position * k2;

k2 = k1->rChild;
k1->rChild = k2->lChild;
k2->lChild = k1;

k1->height = avl_tree_max(avl_tree_height(k1->lChild), avl_tree_height(k1->rChild)) + 1;
k2->height = avl_tree_max(avl_tree_height(k2->lChild), avl_tree_height(k2->rChild)) + 1;

return k2;
}

Position * avl_tree_double_rotate_with_left(AVL_TREE * k3) { /* Rotate between k1 and k2 */ k3->lChild = avl_tree_single_rotate_with_right(k3->lChild); /* Rotate between k2 and k3 */ return avl_tree_single_rotate_with_left(k3); }

Position * avl_tree_double_rotate_with_right(AVL_TREE * k1)
{
/* Rotate between k2 and k3 */
k1->rChild = avl_tree_single_rotate_with_left(k1->rChild);

/* Rotate between k1 and k2 */
return avl_tree_single_rotate_with_right(k1);
}

AVL_TREE * avl_tree_insert(AVL_TREE * tree, ElementType value)
{
if(NULL == tree)
{
tree = (AVL_TREE *)malloc(sizeof(AVL_TREE));
if(NULL == tree)
printf("AVL_TREE malloc failed\n");
else
{
tree->value = value;
tree->height = 0;
tree->lChild = tree->rChild = NULL;
}
}
else if(tree->value > value)
{
tree->lChild = avl_tree_insert(tree->lChild, value);
if(avl_tree_height(tree->lChild) - avl_tree_height(tree->rChild) == 2)
{
if(value < tree->lChild->value)
tree = avl_tree_single_rotate_with_left(tree);
else
tree = avl_tree_double_rotate_with_left(tree);
}
}
else if(tree->value < value)
{
tree->rChild = avl_tree_insert(tree->rChild, value);
if(avl_tree_height(tree->rChild)- avl_tree_height(tree->lChild) == 2)
{
if(value > tree->rChild->value)
tree = avl_tree_single_rotate_with_right(tree);
else
tree = avl_tree_double_rotate_with_right(tree);
}
}

tree->height = avl_tree_max(avl_tree_height(tree->lChild), avl_tree_height(tree->rChild)) + 1;

return tree;
}

Node * avl_tree_delete(AVL_TREE * tree, ElementType value)
{
AVL_TREE * temp = NULL;

if(NULL == tree)
{
printf("Not found the element\n");
}
else if(value > tree->value) /* Go Right */
{
tree->rChild = avl_tree_delete(tree->rChild, value);
}
else if(value < tree->value) /* Go Left */
{
tree->lChild = avl_tree_delete(tree->lChild, value);
}
else if(tree->lChild && tree->rChild) /* Two Children */
{
temp = avl_tree_find_min(tree->rChild);

tree->value = temp->value;
tree->rChild = avl_tree_delete(tree->rChild, tree->value);
}
else /* one or zero Children */
{
temp = tree;
if(NULL == tree->lChild)
{
tree = tree->rChild;
}
else if(NULL == tree->rChild)
{
tree = tree->lChild;
}

free(temp);
}

if(tree) /* Ignore the free node */
{
/* Update the height of tree */
tree->height = avl_tree_max(avl_tree_height(tree->lChild), avl_tree_height(tree->rChild)) + 1;

if(avl_tree_height(tree->lChild) - avl_tree_height(tree->rChild) == 2)
{
if(tree->lChild->rChild)
tree = avl_tree_double_rotate_with_left(tree);
else
tree = avl_tree_single_rotate_with_left(tree);
}
else if(avl_tree_height(tree->rChild)- avl_tree_height(tree->lChild) == 2)
{
if(tree->rChild->lChild)
tree = avl_tree_double_rotate_with_right(tree);
else
tree = avl_tree_single_rotate_with_right(tree);
}
}

return tree;
}

void avl_tree_destroy(AVL_TREE * tree)
{
if(tree)
{
if(tree->lChild)
avl_tree_destroy(tree->lChild);
if(tree->rChild)
avl_tree_destroy(tree->rChild);

free(tree);
}
}

void avl_tree_main(void)
{
AVL_TREE * tree = NULL;
//int i=0;

//for(i=1; i<=127; i++)
// tree = avl_tree_insert(tree, i);
#if 0
tree = avl_tree_insert(tree, 7);
tree = avl_tree_insert(tree, 6);
tree = avl_tree_insert(tree, 10);
tree = avl_tree_insert(tree, 5);
tree = avl_tree_insert(tree, 13);
tree = avl_tree_insert(tree, 8);
tree = avl_tree_insert(tree, 11);
#endif
#if 0
tree = avl_tree_insert(tree, 5);
tree = avl_tree_insert(tree, 3);
tree = avl_tree_insert(tree, 6);
tree = avl_tree_insert(tree, 4);
#endif
#if 0
tree = avl_tree_insert(tree, 5);
tree = avl_tree_insert(tree, 2);
tree = avl_tree_insert(tree, 8);
tree = avl_tree_insert(tree, 1);
tree = avl_tree_insert(tree, 4);
tree = avl_tree_insert(tree, 7);
tree = avl_tree_insert(tree, 3);
#endif
#if 0
tree = avl_tree_insert(tree, 7);
tree = avl_tree_insert(tree, 6);
tree = avl_tree_insert(tree, 8);
tree = avl_tree_insert(tree, 5);
tree = avl_tree_insert(tree, 9);
tree = avl_tree_insert(tree, 10);
#endif
#if 0
tree = avl_tree_insert(tree, 8);
tree = avl_tree_insert(tree, 3);
tree = avl_tree_insert(tree, 10);
tree = avl_tree_insert(tree, 2);
tree = avl_tree_insert(tree, 5);
tree = avl_tree_insert(tree, 9);
tree = avl_tree_insert(tree, 11);
tree = avl_tree_insert(tree, 1);
tree = avl_tree_insert(tree, 4);
tree = avl_tree_insert(tree, 6);
tree = avl_tree_insert(tree, 12);
tree = avl_tree_insert(tree, 7);
#endif
#if 1
tree = avl_tree_insert(tree, 3);
tree = avl_tree_insert(tree, 2);
tree = avl_tree_insert(tree, 4);
tree = avl_tree_insert(tree, 1);
#endif
tree_visual_create(tree, "tree_insert.dot");

Node * min = avl_tree_find_min(tree);
printf("min value : %d\n", min->value);

Node * max = avl_tree_find_max(tree);
printf("max value : %d\n", max->value);

Node * find = avl_tree_find(tree, 2);
if(find)
printf("find value : %d\n", find->value);
else
printf("Cannot find the value\n");

tree = avl_tree_delete(tree, 4);
tree_visual_create(tree, "tree_delete.dot");

avl_tree_destroy(tree);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 数据结构 AVL