基本数据结构之AVL树
2013-08-25 15:29
344 查看
AVL树即自平衡二叉查找树。在AVL树中,任何两个结点的两个子树的高度最大差别为1,所以AVL树也被称为高度平衡树。
AVL树在插入和删除和查找的时间复杂度在平均和最坏情况下都是O(log N),插入和删除需要通过1次或者多次旋转重新使树达到平衡。
怎么判断AVL树是平衡的呢?需要通过平衡因子来来判断,结点的平衡因子是是它的左子树高度减去右子树高度.平衡因子为1、0、-1的结点是平衡的。反之,则是不平衡的。
几种旋转的情况:
1:RR旋转
初始: c
/
b
现在插入一个元素a,如下图所示, 这时,AVL已经不平衡了,经过向右旋转--> b ,此时,树平衡了。
c / \
/ a c
b
/
a
2:LL 旋转
初始: c
\
b
现在插入一个元素a,如下图所示,这是AVL已经不平衡了,经过向左旋转--> b ,此时,树平衡了
c / \
\ c a
b
\
a
3:LR旋转
初始: c
/
b
在b的右子树插入结点,需要经过两次旋转,首先将a向左旋转,然后将c向右旋转:
c c b
/ / / \
b -----> b ----> a c
\ /
a a
4:RL旋转
初始: c
\
b
在b的左子树插入结点a,首相将a向右旋转,然后将c向左旋转。
c c b
\ \ / \
b ----> b ---> c a
/ \
a a
了解了以上四种旋转方式,在接下来的AVL树的插入或阐述操作中进行平衡操作时就更容易理解了。
下面具体讲解下AVL树的实现。
//////////////////////////////////////////////////////////////////////////////////////////
/* AVL with c implentation*/
typedef enum { LEFT = 0, RIGHT = 1 } direction_t;
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
#define OTHER_DIR(x) direction_t( 1 - (x) )
typedef struct avl_node { DATA_TYPE data; short bal; strutc avl_node *subtree[2];}AVLnode_t, *AVLtree_t;/* avl_node */
const AVLtree_t *AVLnull = ((AVLtree_t)NULL);
/* * rotate_once() -- rotate a given node in the given direction * to restore the balance of a tree */short rotate_once(AVLtree_t *rootp, direction_t dir){ direction_t other_dir = OTHER_DIR(dir); /* opposite of "dir" */ AVLtree_t old_root = *rootp; /* copy of original root */ short ht_unchanged; /* true if height unchanged */ /* Here we need to take into account the special case that occurs ** when a single rotation was made but the HEIGHT of the rotated ** tree did NOT change as a result of the rotation (we will need ** this later) */ ht_unchanged = ((*rootp)->subtree[other_dir]->bal) ? FALSE : TRUE; /* assign new root */ *rootp = old_root->subtree[other_dir]; /* new-root exchanges it's "dir" subtree for it's parent */ old_root->subtree[other_dir] = (*rootp)->subtree[dir]; (*rootp)->subtree[dir] = old_root; /* update balances */ old_root->bal = -(dir == LEFT ? --((*rootp)->bal) : ++((*rootp)->bal)); return ht_unchanged; }/* rotate_once */
/* rotate_twice() -- rotate a given node in the given direction * and then in the opposite direction * to restore the balance of a tree */void rotate_twice(AVLtree *rootp, direction_t dir) { direction_t other_dir = OTHER_DIR(dir); AVLtree_t old_root = *rootp; AVLtree_t old_other_dir_subtree = (*rootp)->subtree[other_dir];
/* assign new root */ *rootp = old_root->subtree[other_dir]->subtree[dir];
/* new-root exchanges it's "dir" subtree for it's grandparent */ old_root->subtree[other_dir] = (*rootp)->subtree[dir]; (*rootp)->subtree[dir] = old_root;
/* new-root exchanges it's "other-dir" subtree for it's parent */ old_other_dir_subtree->subtree[dir] = (*rootp)->subtree[other_dir]; (*rootp)->subtree[other_dir] = old_other_dir_subtree;
/* update balances */ (*rootp)->subtree[LEFT]->bal = -MAX((*rootp)->bal, 0); (*rootp)->subtree[RIGHT]->bal = -MIN((*rootp)->bal, 0); (*rootp)->bal = 0;
}/* rotate_twice */
/* Balance Definitions */enum { LEFT_HEAVY = -1, BALANCED = 0, RIGHT_HEAVY = 1 };#define LEFT_IMBALANCE(nd) ( (nd)->bal < LEFT_HEAVY )#define RIGHT_IMBALANCE(nd) ( (nd)->bal > RIGHT_HEAVY )
/* * balance() -- determines and performs the sequence of rotations needed * (if any) to restore the balance of a given tree. * * Returns 1 if tree height changed due to rotation; 0 otherwise */ short balance(AVLtree_t *rootp) { short special_case = FALSE;
if (LEFT_IMBALANCE(*rootp)) { /* need a right rotation */ if ((*rootp)->subtree[LEFT]->bal == RIGHT_HEAVY) { rotate_twice(rootp, RIGHT); /* double RL rotation needed */ } else { /* single RR rotation needed */ special_case = rotate_once(rootp, RIGHT); } } else if (RIGHT_IMBALANCE(*rootp)) { /* need a left rotation */ if ((*rootp)->subtree[RIGHT]->bal == LEFT_HEAVY) { rotate_twice(rootp, LEFT); /* double LR rotation needed */ } else { /* single LL rotation needed */ special_case = rotate_once(rootp, LEFT); } } else { return HEIGHT_UNCHANGED; /* no rotation occurred */ }
return (special_case) ? HEIGHT_UNCHANGED : HEIGHT_CHANGED; }/* balance */ /* * ckalloc(size) -- allocate space; check for success */ void * ckalloc(unsigned size) { void *ptr;
if ((ptr = malloc(size)) == NULL) { fprintf(stderr, "Unable to allocate storage."); exit(1); }/* if */
return ptr; }/* ckalloc */
/* * new_node() -- get space for a new node and its data; * return the address of the new node */ AVLtree_t new_node(void *data, unsigned size) { AVLtree_t root;
root = (AVLtree_t) ckalloc(sizeof(AVLnode)); root->data = (void *) ckalloc(size); memmove(root->data, data, size); root->bal = BALANCED; root->subtree[LEFT] = root->subtree[RIGHT] = AVLnull;
return root; }/* new_node */
/* * free_node() -- free space for a node and its data! * reset the node pointer to NULL */ void free_node(AVLtree_t *rootp) { free((void *) *rootp); *rootp = AVLnull; }/* free_node */
/* * node_type() -- determine the number of null pointers for a given * node in an AVL tree, Returns a value of type node_t * which is an enumeration type with the following * values: * * IS_TREE -- both subtrees are non-empty * IS_LBRANCH -- left subtree is non-empty; right is empty * IS_RBRANCH -- right subtree is non-empty; left is empty * IS_LEAF -- both subtrees are empty * IS_NULL -- given tree is empty */ typedef enum { IS_TREE, IS_LBRANCH, IS_RBRANCH, IS_LEAF, IS_NULL } node_t; node_t node_type(AVLtree_t tree) { if (tree == AVLnull) { return IS_NULL; } else if ((tree->subtree[LEFT] != AVLnull) && (tree->subtree[RIGHT] != AVLnull)) { return IS_TREE; } else if (tree->subtree[LEFT] != AVLnull) { return IS_LBRANCH; } else if (tree->subtree[RIGHT] != AVLnull) { return IS_RBRANCH; } else { return IS_LEAF; } }/* node_type */ /* * avl_min() -- comparator used to find the minimal element in a tree */ int avl_min(void *el1, void *el2, node_t nd_typ) { if ((nd_typ == IS_RBRANCH) || (nd_typ == IS_LEAF)) { return 0; /* left subtree is empty -- this is the minimum */ } else { return -1; /* keep going left */ } }/* avl_min */
/* * avl_max() -- comparator used to find the maximal element in a tree */ int avl_max(void *el1, void *el2, node_t nd_typ) { if ((nd_typ == IS_LBRANCH) || (nd_typ == IS_LEAF)) { return 0; /* right subtree is empty -- this is the maximum */ } else { return 1; /* keep going right */ } }/* avl_max */ /* * avl_compare() -- compare an item with a node-item in an avl tree */ int avl_compare(void *el1, void *el2, node_t nd_typ, int (*el_cmp)(...)) { if ((el_cmp == avl_min) || (el_cmp == avl_max)) { return (*el_cmp)(el1, el2, nd_typ); } else { return (*el_cmp)(el1, el2); } }/* avl_compare */
/* * avl_insert() -- insert an item into the given tree * * PARAMETERS: * data -- a pointer to a pointer to the data to add; * On exit, *data is NULL if insertion succeeded, * otherwise address of the duplicate key * rootp -- a pointer to an AVL tree * compar -- name of the function to compare 2 data items */ short avl_insert(void **data, AVLtree_t *rootp, int (*el_cmp)(...)) { short increase; int cmp;
if (*rootp == AVLnull) { /* insert new node here */ *rootp = new_node(*data, SIZE_OF_DATA); *data = NULL; /* set return value in data */ return HEIGHT_CHANGED; }/* if */
cmp = (*el_cmp)(*data, (*rootp)->data); /* compare data items */
if (cmp < 0) { /* insert into the left subtree */ increase = -avl_insert(data, &((*rootp)->subtree[LEFT]), el_cmp); if (*data != NULL) return HEIGHT_UNCHANGED; } else if (cmp > 0) { /* insert into the right subtree */ increase = avl_insert(data, &((*rootp)->subtree[RIGHT]), el_cmp); if (*data != NULL) return HEIGHT_UNCHANGED; } else { /* data already exists */ *data = (*rootp)->data; /* set return value in data */ return HEIGHT_UNCHANGED; }
(*rootp)->bal += increase; /* update balance factor */
/********************************************************************** * re-balance if needed -- height of current tree increases only if its * subtree height increases and the current tree needs no rotation. **********************************************************************/ if (increase && (*rootp)->bal) { return (1 - balance(rootp)); } else { return HEIGHT_UNCHANGED; } }/* avl_insert */
/* * avl_delete() -- delete an item from the given tree * * PARAMETERS: * data -- a pointer to a pointer to the key to delete * On exit, *data points to the deleted data item * (or NULL if deletion failed). * rootp -- a pointer to an AVL tree * compar -- name of function to compare 2 data items */ short avl_delete(void **data, AVLtree_t *rootp, int (*el_cmp)(...)) { short decrease; int cmp; AVLtree_t old_root = *rootp; node_t nd_typ = node_type(*rootp); direction_t dir = (nd_typ == IS_LBRANCH) ? LEFT : RIGHT;
if (*rootp == AVLnull) { /* data not found */ *data = NULL; /* set return value in data */ return HEIGHT_UNCHANGED; }/* if */
/* compare data items */ /* NOTE the extra parameter to compare this time */ cmp = el_cmp(*data, (*rootp)->data, nd_typ);
if (cmp < 0) { /* delete from left subtree */ decrease = -avl_delete(data, &((*rootp)->subtree[LEFT]), el_cmp); if (*data == NULL) return HEIGHT_UNCHANGED; } else if (cmp > 0) { /* delete from right subtree */ decrease = avl_delete(data, &((*rootp)->subtree[RIGHT]), el_cmp); if (*data == NULL) return HEIGHT_UNCHANGED; } else {
/********************************************************************** * At this point we know that if "cmp" is zero then "*rootp" points to * the node that we need to delete. There are three cases: * * 1) The node is a leaf. Remove it and return. * * 2) The node is a branch (has only 1 child). Make "*rootp" * (the pointer to this node) point to the child. * * 3) The node has two children. We swap data with the successor of * "*rootp" (the smallest item in its right subtree) and delete * the successor from the right subtree of "*rootp". The * identifier "decrease" should be reset if the subtree height * decreased due to the deletion of the successor of "rootp". **********************************************************************/
/* cmp == 0 */ *data = (*rootp)->data; /* set return value in data */
switch (nd_typ) { /* what kind of node are we removing? */ case IS_LEAF : free_node(rootp); /* free the leaf, its height */ return HEIGHT_CHANGED; /* changes from 1 to 0, return 1 */
case IS_RBRANCH : /* only child becomes new root */ case IS_LBRANCH : *rootp = (*rootp)->subtree[dir]; free_node(&old_root); /* free the deleted node */ return HEIGHT_CHANGED; /* just shortened "dir" subtree */
case IS_TREE : decrease = avl_delete(&((*rootp)->data), &((*rootp)->subtree[RIGHT]), avl_min); } /* switch */ } /* else */
(*rootp)->bal -= decrease; /* update balance factor */
/********************************************************************** * Rebalance if necessary -- the height of current tree changes if one * of two things happens: (1) a rotation was performed which changed * the height of the subtree (2) the subtree height decreased and now * matches the height of its other subtree (so the current tree now * has a zero balance when it previously did not). **********************************************************************/ if (decrease && (*rootp)->bal) { /* return 1 if height */ return balance(rootp); /* changed due to rotation */ } else if (decrease && !(*rootp)->bal) { /* or if balance is 0 from */ return HEIGHT_CHANGED; /* height decrease of subtree */ } else { return HEIGHT_UNCHANGED; } }/* avl_delete */
以上代码选自:libavl
AVL树在插入和删除和查找的时间复杂度在平均和最坏情况下都是O(log N),插入和删除需要通过1次或者多次旋转重新使树达到平衡。
怎么判断AVL树是平衡的呢?需要通过平衡因子来来判断,结点的平衡因子是是它的左子树高度减去右子树高度.平衡因子为1、0、-1的结点是平衡的。反之,则是不平衡的。
几种旋转的情况:
1:RR旋转
初始: c
/
b
现在插入一个元素a,如下图所示, 这时,AVL已经不平衡了,经过向右旋转--> b ,此时,树平衡了。
c / \
/ a c
b
/
a
2:LL 旋转
初始: c
\
b
现在插入一个元素a,如下图所示,这是AVL已经不平衡了,经过向左旋转--> b ,此时,树平衡了
c / \
\ c a
b
\
a
3:LR旋转
初始: c
/
b
在b的右子树插入结点,需要经过两次旋转,首先将a向左旋转,然后将c向右旋转:
c c b
/ / / \
b -----> b ----> a c
\ /
a a
4:RL旋转
初始: c
\
b
在b的左子树插入结点a,首相将a向右旋转,然后将c向左旋转。
c c b
\ \ / \
b ----> b ---> c a
/ \
a a
了解了以上四种旋转方式,在接下来的AVL树的插入或阐述操作中进行平衡操作时就更容易理解了。
下面具体讲解下AVL树的实现。
//////////////////////////////////////////////////////////////////////////////////////////
/* AVL with c implentation*/
typedef enum { LEFT = 0, RIGHT = 1 } direction_t;
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
#define OTHER_DIR(x) direction_t( 1 - (x) )
typedef struct avl_node { DATA_TYPE data; short bal; strutc avl_node *subtree[2];}AVLnode_t, *AVLtree_t;/* avl_node */
const AVLtree_t *AVLnull = ((AVLtree_t)NULL);
/* * rotate_once() -- rotate a given node in the given direction * to restore the balance of a tree */short rotate_once(AVLtree_t *rootp, direction_t dir){ direction_t other_dir = OTHER_DIR(dir); /* opposite of "dir" */ AVLtree_t old_root = *rootp; /* copy of original root */ short ht_unchanged; /* true if height unchanged */ /* Here we need to take into account the special case that occurs ** when a single rotation was made but the HEIGHT of the rotated ** tree did NOT change as a result of the rotation (we will need ** this later) */ ht_unchanged = ((*rootp)->subtree[other_dir]->bal) ? FALSE : TRUE; /* assign new root */ *rootp = old_root->subtree[other_dir]; /* new-root exchanges it's "dir" subtree for it's parent */ old_root->subtree[other_dir] = (*rootp)->subtree[dir]; (*rootp)->subtree[dir] = old_root; /* update balances */ old_root->bal = -(dir == LEFT ? --((*rootp)->bal) : ++((*rootp)->bal)); return ht_unchanged; }/* rotate_once */
/* rotate_twice() -- rotate a given node in the given direction * and then in the opposite direction * to restore the balance of a tree */void rotate_twice(AVLtree *rootp, direction_t dir) { direction_t other_dir = OTHER_DIR(dir); AVLtree_t old_root = *rootp; AVLtree_t old_other_dir_subtree = (*rootp)->subtree[other_dir];
/* assign new root */ *rootp = old_root->subtree[other_dir]->subtree[dir];
/* new-root exchanges it's "dir" subtree for it's grandparent */ old_root->subtree[other_dir] = (*rootp)->subtree[dir]; (*rootp)->subtree[dir] = old_root;
/* new-root exchanges it's "other-dir" subtree for it's parent */ old_other_dir_subtree->subtree[dir] = (*rootp)->subtree[other_dir]; (*rootp)->subtree[other_dir] = old_other_dir_subtree;
/* update balances */ (*rootp)->subtree[LEFT]->bal = -MAX((*rootp)->bal, 0); (*rootp)->subtree[RIGHT]->bal = -MIN((*rootp)->bal, 0); (*rootp)->bal = 0;
}/* rotate_twice */
/* Balance Definitions */enum { LEFT_HEAVY = -1, BALANCED = 0, RIGHT_HEAVY = 1 };#define LEFT_IMBALANCE(nd) ( (nd)->bal < LEFT_HEAVY )#define RIGHT_IMBALANCE(nd) ( (nd)->bal > RIGHT_HEAVY )
/* * balance() -- determines and performs the sequence of rotations needed * (if any) to restore the balance of a given tree. * * Returns 1 if tree height changed due to rotation; 0 otherwise */ short balance(AVLtree_t *rootp) { short special_case = FALSE;
if (LEFT_IMBALANCE(*rootp)) { /* need a right rotation */ if ((*rootp)->subtree[LEFT]->bal == RIGHT_HEAVY) { rotate_twice(rootp, RIGHT); /* double RL rotation needed */ } else { /* single RR rotation needed */ special_case = rotate_once(rootp, RIGHT); } } else if (RIGHT_IMBALANCE(*rootp)) { /* need a left rotation */ if ((*rootp)->subtree[RIGHT]->bal == LEFT_HEAVY) { rotate_twice(rootp, LEFT); /* double LR rotation needed */ } else { /* single LL rotation needed */ special_case = rotate_once(rootp, LEFT); } } else { return HEIGHT_UNCHANGED; /* no rotation occurred */ }
return (special_case) ? HEIGHT_UNCHANGED : HEIGHT_CHANGED; }/* balance */ /* * ckalloc(size) -- allocate space; check for success */ void * ckalloc(unsigned size) { void *ptr;
if ((ptr = malloc(size)) == NULL) { fprintf(stderr, "Unable to allocate storage."); exit(1); }/* if */
return ptr; }/* ckalloc */
/* * new_node() -- get space for a new node and its data; * return the address of the new node */ AVLtree_t new_node(void *data, unsigned size) { AVLtree_t root;
root = (AVLtree_t) ckalloc(sizeof(AVLnode)); root->data = (void *) ckalloc(size); memmove(root->data, data, size); root->bal = BALANCED; root->subtree[LEFT] = root->subtree[RIGHT] = AVLnull;
return root; }/* new_node */
/* * free_node() -- free space for a node and its data! * reset the node pointer to NULL */ void free_node(AVLtree_t *rootp) { free((void *) *rootp); *rootp = AVLnull; }/* free_node */
/* * node_type() -- determine the number of null pointers for a given * node in an AVL tree, Returns a value of type node_t * which is an enumeration type with the following * values: * * IS_TREE -- both subtrees are non-empty * IS_LBRANCH -- left subtree is non-empty; right is empty * IS_RBRANCH -- right subtree is non-empty; left is empty * IS_LEAF -- both subtrees are empty * IS_NULL -- given tree is empty */ typedef enum { IS_TREE, IS_LBRANCH, IS_RBRANCH, IS_LEAF, IS_NULL } node_t; node_t node_type(AVLtree_t tree) { if (tree == AVLnull) { return IS_NULL; } else if ((tree->subtree[LEFT] != AVLnull) && (tree->subtree[RIGHT] != AVLnull)) { return IS_TREE; } else if (tree->subtree[LEFT] != AVLnull) { return IS_LBRANCH; } else if (tree->subtree[RIGHT] != AVLnull) { return IS_RBRANCH; } else { return IS_LEAF; } }/* node_type */ /* * avl_min() -- comparator used to find the minimal element in a tree */ int avl_min(void *el1, void *el2, node_t nd_typ) { if ((nd_typ == IS_RBRANCH) || (nd_typ == IS_LEAF)) { return 0; /* left subtree is empty -- this is the minimum */ } else { return -1; /* keep going left */ } }/* avl_min */
/* * avl_max() -- comparator used to find the maximal element in a tree */ int avl_max(void *el1, void *el2, node_t nd_typ) { if ((nd_typ == IS_LBRANCH) || (nd_typ == IS_LEAF)) { return 0; /* right subtree is empty -- this is the maximum */ } else { return 1; /* keep going right */ } }/* avl_max */ /* * avl_compare() -- compare an item with a node-item in an avl tree */ int avl_compare(void *el1, void *el2, node_t nd_typ, int (*el_cmp)(...)) { if ((el_cmp == avl_min) || (el_cmp == avl_max)) { return (*el_cmp)(el1, el2, nd_typ); } else { return (*el_cmp)(el1, el2); } }/* avl_compare */
/* * avl_insert() -- insert an item into the given tree * * PARAMETERS: * data -- a pointer to a pointer to the data to add; * On exit, *data is NULL if insertion succeeded, * otherwise address of the duplicate key * rootp -- a pointer to an AVL tree * compar -- name of the function to compare 2 data items */ short avl_insert(void **data, AVLtree_t *rootp, int (*el_cmp)(...)) { short increase; int cmp;
if (*rootp == AVLnull) { /* insert new node here */ *rootp = new_node(*data, SIZE_OF_DATA); *data = NULL; /* set return value in data */ return HEIGHT_CHANGED; }/* if */
cmp = (*el_cmp)(*data, (*rootp)->data); /* compare data items */
if (cmp < 0) { /* insert into the left subtree */ increase = -avl_insert(data, &((*rootp)->subtree[LEFT]), el_cmp); if (*data != NULL) return HEIGHT_UNCHANGED; } else if (cmp > 0) { /* insert into the right subtree */ increase = avl_insert(data, &((*rootp)->subtree[RIGHT]), el_cmp); if (*data != NULL) return HEIGHT_UNCHANGED; } else { /* data already exists */ *data = (*rootp)->data; /* set return value in data */ return HEIGHT_UNCHANGED; }
(*rootp)->bal += increase; /* update balance factor */
/********************************************************************** * re-balance if needed -- height of current tree increases only if its * subtree height increases and the current tree needs no rotation. **********************************************************************/ if (increase && (*rootp)->bal) { return (1 - balance(rootp)); } else { return HEIGHT_UNCHANGED; } }/* avl_insert */
/* * avl_delete() -- delete an item from the given tree * * PARAMETERS: * data -- a pointer to a pointer to the key to delete * On exit, *data points to the deleted data item * (or NULL if deletion failed). * rootp -- a pointer to an AVL tree * compar -- name of function to compare 2 data items */ short avl_delete(void **data, AVLtree_t *rootp, int (*el_cmp)(...)) { short decrease; int cmp; AVLtree_t old_root = *rootp; node_t nd_typ = node_type(*rootp); direction_t dir = (nd_typ == IS_LBRANCH) ? LEFT : RIGHT;
if (*rootp == AVLnull) { /* data not found */ *data = NULL; /* set return value in data */ return HEIGHT_UNCHANGED; }/* if */
/* compare data items */ /* NOTE the extra parameter to compare this time */ cmp = el_cmp(*data, (*rootp)->data, nd_typ);
if (cmp < 0) { /* delete from left subtree */ decrease = -avl_delete(data, &((*rootp)->subtree[LEFT]), el_cmp); if (*data == NULL) return HEIGHT_UNCHANGED; } else if (cmp > 0) { /* delete from right subtree */ decrease = avl_delete(data, &((*rootp)->subtree[RIGHT]), el_cmp); if (*data == NULL) return HEIGHT_UNCHANGED; } else {
/********************************************************************** * At this point we know that if "cmp" is zero then "*rootp" points to * the node that we need to delete. There are three cases: * * 1) The node is a leaf. Remove it and return. * * 2) The node is a branch (has only 1 child). Make "*rootp" * (the pointer to this node) point to the child. * * 3) The node has two children. We swap data with the successor of * "*rootp" (the smallest item in its right subtree) and delete * the successor from the right subtree of "*rootp". The * identifier "decrease" should be reset if the subtree height * decreased due to the deletion of the successor of "rootp". **********************************************************************/
/* cmp == 0 */ *data = (*rootp)->data; /* set return value in data */
switch (nd_typ) { /* what kind of node are we removing? */ case IS_LEAF : free_node(rootp); /* free the leaf, its height */ return HEIGHT_CHANGED; /* changes from 1 to 0, return 1 */
case IS_RBRANCH : /* only child becomes new root */ case IS_LBRANCH : *rootp = (*rootp)->subtree[dir]; free_node(&old_root); /* free the deleted node */ return HEIGHT_CHANGED; /* just shortened "dir" subtree */
case IS_TREE : decrease = avl_delete(&((*rootp)->data), &((*rootp)->subtree[RIGHT]), avl_min); } /* switch */ } /* else */
(*rootp)->bal -= decrease; /* update balance factor */
/********************************************************************** * Rebalance if necessary -- the height of current tree changes if one * of two things happens: (1) a rotation was performed which changed * the height of the subtree (2) the subtree height decreased and now * matches the height of its other subtree (so the current tree now * has a zero balance when it previously did not). **********************************************************************/ if (decrease && (*rootp)->bal) { /* return 1 if height */ return balance(rootp); /* changed due to rotation */ } else if (decrease && !(*rootp)->bal) { /* or if balance is 0 from */ return HEIGHT_CHANGED; /* height decrease of subtree */ } else { return HEIGHT_UNCHANGED; } }/* avl_delete */
以上代码选自:libavl
相关文章推荐
- 基本数据结构之AVL树-简单实现
- [基本数据结构]网格(Mesh)和几何体(Geometry)
- 基本数据结构:树(tree)
- caffe的基本数据结构
- 基本数据结构-栈的实现及其运用
- PHP数据结构之五:栈的PHP的实现和栈的基本操作
- 【C++研发面试笔记】12. 基本数据结构-B树簇
- Redis源码学习4-基本数据结构之字典
- 数据结构和算法的基本介绍
- C语言实现基本数据结构之二叉树
- 算法导论第10章基本数据结构10.1栈
- 数据结构基本算法:图的存储(以邻接链表为例)
- 《算法导论》读书笔记之第10章 基本数据结构
- 数据结构基本知识点(二)
- 数据结构-AVL树
- runtime 类和对象的使用和基本的数据结构
- 基本数据结构
- nginx 源码学习(五) 基本数据结构 ngx_list_t
- 数据结构和算法的基本知识点复习
- 数据结构-栈的基本操作实现