平衡二叉树( AVL树 ):
二叉排序树的查找与树的形态密切相关,当树的形态比较均衡时查找效率最高,当树的形态偏向于某一个方向是效率迅速降低,而一颗二叉树的形态取决于数据插入的先后顺序,如果构造一颗较均衡的二叉树比较困难。那有没有合适的方法把一颗不平衡的树调整为平衡的二叉树,答案是肯定的。这就是平衡二叉树在1962年由Adelson-Velskii和Landis提出的,所以又叫AVL树。
其特点是:或者是一颗空树,或者是满足下列性质的二叉树:树的左子树和右子树的深度之差的绝对值不大于1且左右子树也满足上述性质。
平衡因子:二叉树上任一结点的左子树深度减去右子树的深度称为该结点的平衡因子,易知平衡二叉树中所有结点的因子只可能为0,-1和1.
平衡二叉排序树的在平衡因子绝对值等于2时开始调整到绝对值为1或0,在平衡因子绝对值为2时,二叉排序树会出现四种不同的情况的树形,因此这时需要分别单独讨论来降低平衡因子。由于前面画的图都没有上传上来,暂时还不知道CSDN博客里怎么上传图,所以这里暂不做详解。如果要讨论四种情况,请参见源代码细细分析:
#include <iostream.h> #include <string.h> #define NUM 10 typedef int KeyType; class AVLTree; class AVLNode { public: KeyType key; //任意一结点的左子树深度减去右子树的 //深度称为该节点的平衡因子. int bf; //记录平衡因子 AVLNode *lchild; AVLNode *rchild; AVLNode() { lchild = NULL; rchild = NULL; bf = 0; } }; //平衡二叉排序树 class AVLTree { public: AVLNode *root; AVLTree() { root = NULL; } AVLNode* LL_Rotate( AVLNode *a ); //LL(顺时针)型调整 AVLNode* RR_Rotate( AVLNode *a ); //RR(逆时针)型调整 AVLNode* LR_Rotate( AVLNode *a ); //LR(先逆后顺)型调整 AVLNode* RL_Rotate( AVLNode *a ); //RL(先顺后逆)型调整 void AVLInsert( AVLNode *&pavlt, AVLNode *s ); //插入一个新结点 }; /** * LL(顺时针)型调整 * */ AVLNode* AVLTree::LL_Rotate( AVLNode *a ) { if( a == NULL ) { cout << “the pointer is null!” << endl; return NULL; } AVLNode *b; b = a->lchild; //b指向a的左子树根结点 a->lchild = b->rchild; //b的右子树挂在a的左子树上 b->rchild = a; a->bf = b->bf = 0; return b; } /** * RR(逆时针)型调整 * */ AVLNode* AVLTree::RR_Rotate( AVLNode *a ) { if( a == NULL ) { cout << “the pointer is null!” << endl; return NULL; } AVLNode *b; b = a->rchild; a->rchild = b->lchild; b->lchild = a; a->bf = b->bf = 0; return b; } /** * LR(先逆后顺)型调整 * */ AVLNode* AVLTree::LR_Rotate( AVLNode *a ) { if( a == NULL ) { cout << “the pointer is null!” << endl; return NULL; } AVLNode *b, *c; b = a->lchild; c = b->rchild; a->lchild = c->rchild; b->rchild = c->lchild; c->lchild = b; c->rchild = a; //调整平衡因子 if( c->bf == 1 ) { a->bf = -1; b->bf = 0; } else if( c->bf == -1 ) { a->bf = 0; b->bf = 1; } else { b->bf = a->bf = 0; } c->bf = 0; return c; } /** * RL(先顺后逆)型调整 * */ AVLNode* AVLTree::RL_Rotate( AVLNode *a ) { if( a == NULL ) { cout << “the pointer is null!” << endl; return NULL; } AVLNode *b, *c; b = a->rchild; c = b->lchild; a->rchild = c->lchild; b->lchild = c->rchild; c->lchild = a; c->rchild = b; //调整平衡因子 if( c->bf == 1 ) { a->bf = 0; b->bf = -1; } else if( c->bf == -1 ) { a->bf = 1; b->bf = 0; } else { a->bf = b->bf = 0; } c->bf = 0; return c; } /** * 将结点s插入pavlt为根结点的平衡二叉排序树中 * */ void AVLTree::AVLInsert( AVLNode *&pavlt, AVLNode *s ) { AVLNode *f, *a, *b, *p, *q; if( pavlt == NULL ) { pavlt = s; return; } a = pavlt; f = NULL; p = pavlt; q = NULL; //寻找插入点位置及最小不平衡树的子树 while( p != NULL ) { if( p->key == s->key ) //AVL中已经存在关键字 return; if( p->bf != 0 ) //寻找最小不平衡子树 { a = p; f = q; } q = p; if( s->key < p->key ) p = p->lchild; else p = p->rchild; } if( s->key < q->key ) //将结点*s插入到合适的位置上去 q->lchild = s; else q->rchild = s; p = a; while( p != s ) //插入结点后修改相应的平衡因子 { if( s->key < p->key ) { p->bf++; p = p->lchild; } else { p->bf–; p = p->rchild; } } if( a->bf > -2 && a->bf < 2 ) //插入结点后没有破坏平衡树 return; if( a->bf == 2 ) { b = a->lchild; if( b->bf == 1 ) //结点插在*a的左孩子的左子树中 p = LL_Rotate( a ); //LL型调整 else //结点插在*a的左孩子的右子树中 p = LR_Rotate( a ); //LR型调整 } else { b = a->rchild; if( b->bf == 1 ) //结点插在*a的右孩子的左子树中 p = RL_Rotate( a ); //RL型调整 else //结点插在*a的右孩子的右子树中 p = RR_Rotate( a ); //RR型调整 } if( f == NULL ) //原*a是AVL树的根 pavlt = p; else if( f->lchild == a ) //将新子树链到原结点*a的双亲结点上 f->lchild = p; else f->rchild = p; } /** * 在VC6.0下测试成功 * cheneagle:2009.8.6 */ int main( void ) { int a[NUM] = { 34, 18, 13, 73, 16, 52, 58, 67, 82, 76 }; int i = 0; AVLTree tree; AVLNode pNode[NUM], *p = NULL; for( i = 0; i < NUM; i++ ) { pNode[i].key = a[i]; tree.AVLInsert( p, &pNode[i] ); } return 0; }