AVL树插入、删除的分析与实现
2014-07-10 10:19
369 查看
AVL树基本概念
一棵AVL(Adelson-Velskii and Landis)树满足下面三个条件:是一棵二叉搜索树(Binary Search Tree);
对于树中的每一个结点,其左、右子树的高度差的绝对值小于等于1;
空树的高度定义为-1。
如图1,左边的是一棵AVL树,而右边的则不是(17是不平衡的,其左子树的高度为1,而右子树的高度为-1),但它们都是二叉搜索树。
[align=center]图1 AVL树和二叉搜索树
AVL树在基本的二叉搜索树上加以限制条件来控制树的平衡,施加的条件可以多样化,比如可以要求每个结点的的左右子树高度差的绝对值为0,但这太严格了,实际上只有满二叉树能达到这个要求;若再把限制条件放松一点点,即允许高度差的绝对值不超过1,那么就成了AVL树;如果再把限制条件放松,还可以定义出其它类型的平衡树。
[/align]
AVL树的插入操作
插入操作同普通的二叉搜索树的插入操作时一样的,可以参考数据结构教材,这儿不详述。对于AVL树,插入一个新结点后,可能导致上述条件2被破坏。导致这种情况发生的情形有4种,下面只分析其中两种,另外两种情况是对称的。我们假设首先被打破平衡状态的结点为α。情形1——插入到α的左孩子的左子树中
如图2左边所示,此时可以将α进行右旋转,得到右边的结果,旋转后的根节点变成了β,整棵树维持平衡。[align=center]图2 左-左插入及平衡恢复
[/align]
情形2——插入到α的左孩子的右子树中
如图3左边所示,注意:此时的B和C高度不可能同时为h-1。对于这种情形,需要进行两次旋转,先对β进行左旋转,然后对α进行右旋转,整棵树维持平衡。[align=center]图3 左-右插入及平衡恢复[/align]
情形3——插入到α的右孩子的右子树中
这与情形1是对称的。情形4——插入到α的右孩子的左子树中
这与情形2是对称的。插入操作C语言伪代码
设函数avl_insert()接受参数为一个AvlTree类型的变量以及要插入的键值key,函数返回插入key后的新的AVL树,则伪代码如下:AvlTree avl_insert(AvlTree t, int key) { if (NULL == t) { /* alloc new node here and assign it to t */ } else if (t->key > key) { t->left = avl_insert(t->left, key); if (t is unbalanced) { if (key < t->left->key) t = single_rotate_r(t); /* Left-Left */ else t = double_rotate_lr(t); /* Left-Right */ } } else if (t->key < key) { t->right = avl_insert(t->right, key); if (t is unbalanced) { if (key > t->right->key) t = single_rotate_l(t); /* Right-Right */ else t = double_rotate_rl(t); /* Right-Left */ } } else ; /* duplicate key, do nothing */ /* adjust t's height */ t->height = max(height(t->left), height(t->right)) + 1; return t; }
AVL树的删除操作
删除结点后,我们设第一个被打破平衡状态的结点为α。相应的,删除操作也有4种情况,但其实可以分为两大类:删除的结点属于α的左子树;
删除的结点属于α的右子树。
我们将分析第一类中的两种情形,另外两种情形是类似的。
类别1——删除α的右子树中的某个结点
假设结点被删除后,α的右子树高度为h。情形1——α的左孩子的左子树高度为h+1
这种情形如图4所示,被删除的结点原来位于D中,删除后D的高度由h+1变成了h,导致α失去平衡。我们假设A的高度为h+1,而不用理会B的高度,但可以肯定的是B的高度只能是h或h+1,否则如果B的高度为h-1的话,那么β是不平衡的,这与我们假设的第一个被打破平衡的结点为α是矛盾的。此时只需对α进行右旋转就可以了。[align=center]图4 删除结点的情形1[/align]
情形2——α的左孩子的左子树高度为h
这种情形如图5所示,被删除的结点原来位于D中,删除后D的高度由h+1变成了h,导致α失去平衡。与上面的情形1不同,这次我们假设A的高度为h,那么上面图4中的B高度必为h+1,据此,我们画出图5。按照我们的假设,图5中的B和C的高度不可能同时为h-1(想想为什么?)。此时,先对β进行左旋转,再对α进行右旋转。[align=center]图 5 删除结点的情形2[/align]
类别2——删除α的左子树中的某个结点
情形1——α的右孩子的右子树高度为h+1
这与类别1中的情形1是对称的。情形2——α的右孩子的右子树高度为h
这与类别1中的情形2是对称的。删除操作C语言伪代码
和插入操作类似,这儿不列出它的伪代码,文章末尾会给出完整的AVL插入、删除操作的C语言实现。作为练习,读者可以先思考一下如何实现删除操作,如果你理解了上面讲述的情形1和情形2,那么就不难得出答案,否则你可能还没有完全理解删除操作,可以再多思考思考。AVL树的完整C语言实现
/* * Copyright © 2014 YU Heng-yang. All rights reserved. * * avl_tree.c - Simple implementation of AVL tree. * * Modify key to other types as you like, note also * the prototype of exported functions and key * compare function. * * TODO: * Implements avl_remove() operation, more complicate * than expected. * * 2014-7-7 YU Heng-yang. * * Rev1: * Implementated avl_remove() operation. * * 2014-7-9 YU Hengy-yang. */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <assert.h> #define ALLOC(size) malloc(size) #define FREE(p) free(p) typedef struct AvlTree *AvlTree; struct AvlTree { int key; int height; AvlTree left, right; }; /* exported functions */ AvlTree avl_new(void); AvlTree avl_insert(AvlTree t, int key); AvlTree avl_remove(AvlTree t, int key); AvlTree avl_find(AvlTree t, int key); AvlTree avl_destroy(AvlTree t); void avl_traversal(AvlTree t, void (*apply) (AvlTree t, void *arg), void *arg); /* internal functions */ static AvlTree single_rotate_l(AvlTree t); static AvlTree single_rotate_r(AvlTree t); static AvlTree double_rotate_lr(AvlTree t); static AvlTree double_rotate_rl(AvlTree t); static AvlTree rebalance(AvlTree t); static AvlTree avl_find_max(AvlTree t); static int height(AvlTree t); static int max(int x, int y); static void check(AvlTree t, int d); static void print_tree(AvlTree t); static void print(AvlTree t, void *arg); /* test driver */ static void handcraft_test(int n); static void autorun_test(int n); int main(int argc, char *argv[]) { int n; /* * Sample input: * step1: 13 * step2: 13 4 20 -7 10 15 30 -18 1 8 11 27 7 * step3: enter 13 integers randomly * step4: 20 13 -7 7 30 1 11 27 10 4 -18 15 8 */ puts("How many numb c948 ers you will input?(For example, 5 or enter 0 to skip this step)"); scanf("%d", &n); handcraft_test(n); /* * Sample input: * * 1000 */ puts("How many numbers do you want for autorun?(For example, 5000)"); scanf("%d", &n); autorun_test(n); return 0; } AvlTree avl_new(void) { return NULL; } /* * Draw some pictures to get an insight. * Hint: * There are four cases that need rotation(s) * to rebalance the tree. Tow of them are symmetric to * the other two. Height of empty trees is -1. * Besides calling rebalance(), the code commented * out is another way to rebalance t. * */ AvlTree avl_insert(AvlTree t, int key) { if (NULL == t) { AvlTree newt = ALLOC(sizeof(*newt)); newt->key = key; newt->left = newt->right = NULL; newt->height = 0; t = newt; } else if (t->key > key) { t->left = avl_insert(t->left, key); /* if (height(t->left) - height(t->right) >= 2) { */ /* if (key < t->left->key) */ /* t = single_rotate_r(t); /\* Left-Left *\/ */ /* else */ /* t = double_rotate_lr(t); /\* Left-Right *\/ */ /* } */ t = rebalance(t); } else if (t->key < key) { t->right = avl_insert(t->right, key); /* if (height(t->right) - height(t->left) >= 2) { */ /* if (key > t->right->key) */ /* t = single_rotate_l(t); /\* Right-Right *\/ */ /* else */ /* t = double_rotate_rl(t); /\* Right-Left *\/ */ /* } */ t = rebalance(t); } else ; /* duplicate key, do nothing */ t->height = max(height(t->left), height(t->right)) + 1; return t; } /* * Again, draw some pictures to get an insight. * Hint: * There four cases that need rotation(s) to * rebalance the tree. Two of them are symmetric to * the other two. */ AvlTree avl_remove(AvlTree t, int key) { if (t) { if (t->key > key) { t->left = avl_remove(t->left, key); t = rebalance(t); } else if (t->key < key) { t->right = avl_remove(t->right, key); t = rebalance(t); } else { if (t->left && t->right) { AvlTree lmax = avl_find_max(t->left); t->key = lmax->key; t->left = avl_remove(t->left, lmax->key); /* t may be unbalanced after remove key from t->left */ t = rebalance(t); } else { /* at most one child of t is not empty */ AvlTree ret; if (!t->left) ret = t->right; else ret = t->left; FREE(t); t = ret; } } } if (t) t->height = max(height(t->left), height(t->right)) + 1; return t; } AvlTree avl_find(AvlTree t, int key) { if (t) { if (t->key > key) return avl_find(t->left, key); else if (t->key < key) return avl_find(t->right, key); else return t; } return NULL; } AvlTree avl_destroy(AvlTree t) { if (t) { t->left = avl_destroy(t->left); t->right = avl_destroy(t->right); FREE(t); } return NULL; } void avl_traversal(AvlTree t, void (*apply) (AvlTree t, void *arg), void *arg) { if (t) { assert(apply); avl_traversal(t->left, apply, arg); apply(t, arg); avl_traversal(t->right, apply, arg); } } /* Precondition: t has right child */ static AvlTree single_rotate_l(AvlTree t) { AvlTree rchild; assert(t->right); rchild = t->right; t->right = rchild->left; rchild->left = t; t->height = max(height(t->left), height(t->right)) + 1; rchild->height = max(height(rchild->left), height(rchild->right)) + 1; return rchild; } /* Precondition: t has left child */ static AvlTree single_rotate_r(AvlTree t) { AvlTree lchild; assert(t->left); lchild = t->left; t->left = lchild->right; lchild->right = t; t->height = max(height(t->left), height(t->right)) + 1; lchild->height = max(height(lchild->left), height(lchild->right)) + 1; return lchild; } /* Precondition: t has left child which has right child */ static AvlTree double_rotate_lr(AvlTree t) { assert(t->left && t->left->right); t->left = single_rotate_l(t->left); return single_rotate_r(t); } /* Precondition: t has right child which has left child */ static AvlTree double_rotate_rl(AvlTree t) { assert(t->right && t->right->left); t->right = single_rotate_r(t->right); return single_rotate_l(t); } static AvlTree avl_find_max(AvlTree t) { if (t) while (t->right) t = t->right; return t; } static AvlTree rebalance(AvlTree t) { if (t) { int diff = height(t->left) - height(t->right); assert(diff >= -2 && diff <= 2); /* check(t, 2); */ if (diff == -2) { diff = height(t->right->right) - height(t->left); if (diff > 0) { assert(diff == 1); t = single_rotate_l(t); } else { assert(diff == 0); t = double_rotate_rl(t); } } if (diff == 2) { diff = height(t->left->left) - height(t->right); if (diff > 0) { assert(diff == 1); t = single_rotate_r(t); } else { assert(diff == 0); t = double_rotate_lr(t); } } } return t; } static int height(AvlTree t) { if (NULL == t) return -1; return t->height; } static int max(int x, int y) { return x > y ? x : y; } static void print_tree(AvlTree t) { if (t) { print_tree(t->left); printf("(%d, %d) ", t->key, height(t)); print_tree(t->right); } } static void check(AvlTree t, int d) { if (t) { int diff; check(t->left, d); check(t->right, d); diff = height(t->left) - height(t->right); /* dump out tree */ if (diff < -d || diff > d) { printf("Left height = %d, Right height = %d\n", height(t->left), height(t->right)); print_tree(t); } assert(diff >= -d && diff <= d); } } static void print(AvlTree t, void *arg) { assert(arg); printf((char *)arg, t->key); } void handcraft_test(int ninput) { int i, n; AvlTree tree = avl_new(); /* insert */ for (i = 0; i < ninput; i++) { scanf("%d", &n); tree = avl_insert(tree, n); check(tree, 1); printf("After insert %d: ", n); avl_traversal(tree, print, "%d "); /* in practice, height() will not be exported */ printf(", Height: %d", height(tree)); putchar('\n'); } /* find */ for (i = 0; i < ninput; i++) { scanf("%d", &n); printf("%s\n", avl_find(tree, n) ? "Found" : "Not Found"); } /* remove */ for (i = 0; i < ninput; i++) { scanf("%d", &n); tree = avl_remove(tree, n); check(tree, 1); printf("After remove %d: ", n); avl_traversal(tree, print, "%d "); /* in practice, height() will not be exported */ printf(", Height: %d", height(tree)); putchar('\n'); } tree = avl_destroy(tree); assert(NULL == tree); assert(NULL == avl_find(tree, 100)); assert(NULL == avl_remove(tree, -100)); avl_traversal(tree, print, "%d "); } void autorun_test(int n) { if (n > 0) { int i, *keys; AvlTree tree = avl_new(); keys = ALLOC(n * sizeof(*keys)); /* generate random numbers */ srand(time(NULL)); for (i = 0; i < n; i++) keys[i] = rand(); /* insert one by one */ for (i = 0; i < n; i++) { tree = avl_insert(tree, keys[i]); /* printf("Insert %d, Height %d\n", keys[i], height(tree)); */ } check(tree, 1); printf("AVL tree generated, height is %d\n", height(tree)); /* print_tree(tree); */ /* putchar('\n'); */ /* try to find some of them */ for (i = 0; i < n; i++) { /* make some not found cases*/ int key = i & 1 ? rand() : keys[i]; avl_find(tree, key); /* printf("%d:%s\n", key, avl_find(tree, key) ? "Found":"Not found"); */ } puts("AVL find operation finished."); /* remove one by one */ for (i = 0; i < n; i++) { /* equal chance for remove or not remove */ /* int key = i & 1 ? rand() : keys[i]; */ int key = keys[i]; /* check(tree, 1); */ /* printf("\nBefore remove %d: ", key); */ /* print_tree(tree); */ /* printf("Remove %d\n", key); */ tree = avl_remove(tree, key); /* printf("\nAfter remove %d: ", key); */ /* print_tree(tree); */ /* printf(", Height %d\n", height(tree)); */ } puts("AVL remove operation finished"); tree = avl_destroy(tree); FREE(keys); } }
相关文章推荐
- AVL树的插入删除查找算法实现和分析-1(平衡因子法)
- AVL树的插入删除查找算法实现和分析-2(树高度法)
- AVL树的插入删除查找算法实现和分析-1(平衡因子法)
- AVL树的插入删除查找算法实现和分析-2(树高度法)
- AVL树的插入删除查找算法实现和分析-1
- 转载:二叉查找树原理分析及查找、插入、删除、遍历实现
- AVL树的旋转、插入、删除及遍历C语言实现
- 纯C语言实现的AVL树(插入&删除&前序遍历输出)
- AVL树非递归实现插入和删除例程
- AVL树的插入与删除---Java实现
- AVL树的插入删除分析
- AVL树插入删除算法详解(有图) -- C++语言实现
- AVL树实现(插入删除)
- AVL树的插入_删除操作实现~
- AVL树的插入与删除(均为递归实现)
- 红黑树插入删除节点过程分析 && C代码实现
- 二叉查找树原理分析及查找、插入、删除、遍历实现
- c语言实现线性表的建立,初始化,插入,删除,查找,遍历以及时间复杂度分析
- 堆的建立, 元素插入, 删除的实现...
- AVL树插入和删除源代码