基本数据结构之AVL树
来源:互联网 发布:mac迅雷一打开就闪退 编辑:程序博客网 时间:2024/06/06 01:59
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树
- 基本数据结构之AVL树-简单实现
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 数据结构之AVL树
- 【瓶中的&&心xp主题】_8.25
- js工作随笔
- [转载]HTML5实现多人实时3D游戏
- 什么是Socket
- .Net类库预定义委托之Func
- 基本数据结构之AVL树
- jquery对象扩展小试
- Android 微信分享信息
- 初识JavaScript,Ajax,jQuery,并比较三者关系
- 计算机网络面试题
- Node.js最简单应用
- 如何将自己的生成的DLL写入到WINCE内核中
- ubuntu 修改当前文件夹中所有 文件时间为特定时间
- 【Windows7系统值得推荐的四大特色】