平衡二叉排序树

AVL树介绍

BST是一种查找效率比较高的组织形式,但其平均查找长度受树的形态影响较大,形态比较均匀时查找效率很好,形态明显偏向某一方向时其效率就大大降低。因此,希望有更好的二叉排序树,其形态总是均衡的,查找时能得到最好的效率,这就是平衡二叉排序树。

    平衡二叉排序树(Balanced Binary Tree或Height-Balanced Tree)是在1962年由Adelson-Velskii和Landis提出的,又称AVL树。

    平衡二叉树或者是空树,或者是满足下列性质的二叉树。
⑴:左子树和右子树深度之差的绝对值不大于1;
⑵:左子树和右子树也都是平衡二叉树。
    平衡因子(Balance Factor) :二叉树上结点的左子树的深度减去其右子树深度称为该结点的平衡因子。
    因此,平衡二叉树上每个结点的平衡因子只可能是-1、0和1,否则,只要有一个结点的平衡因子的绝对值大于1, 该二叉树就不是平衡二叉树。
    如果一棵二叉树既是二叉排序树又是平衡二叉树,称为平衡二叉排序树(Balanced Binary Sort Tree) 。

    一般的二叉排序树是不平衡的,若能通过某种方法使其既保持有序性,又具有平衡性,就找到了构造平衡二叉排序树的方法,该方法称为平衡化旋转。
    在对AVL树进行插入或删除一个结点后,通常会影响到从根结点到插入(或删除)结点的路径上的某些结点,这些结点的子树可能发生变化。以插入结点为例,影响有以下几种可能性
◆  以某些结点为根的子树的深度发生了变化; 
◆ 某些结点的平衡因子发生了变化;
◆ 某些结点失去平衡。

沿着插入结点上行到根结点就能找到某些结点,这些结点的平衡因子和子树深度都会发生变化,这样的结点称为失衡结点。

AVL树的创建

关于平衡二叉树的创建插入操作以及对应平衡因子的分析如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


#define MAX_SIZE 100



int keys[] = {5,7,3,2,9,4,8,1,10,6};

typedef struct AVLNode{

	int data;  
	int bf;  //平衡因子  
	struct AVLNode *lchild;  
	struct AVLNode *rchild;  

}AVLNode;

AVLNode* mallocAVLNode(int data){
	AVLNode* root = (AVLNode*)malloc(sizeof(AVLNode));
	root->bf = 0;
	root->data = data;
	root->lchild = NULL;
	root->rchild = NULL;
	return root;
}

void printDataInfo(int i){
	printf("%d ",i);
}


AVLNode* LL_Rotate( AVLNode *a ){//LL(顺时针)型调整 

	if (a == NULL){
		return NULL;
	}

	AVLNode *b = a->lchild;//b指向a的左子树根结点  
	a->lchild = b->rchild; //b的右子树挂在a的左子树上  
	b->rchild = a;

	a->bf = b->bf = 0;
	return b;
}     
AVLNode* RR_Rotate( AVLNode *a ){ //RR(逆时针)型调整  
	if (a == NULL){
		return NULL;
	}

	AVLNode *b = a->rchild;//b指向a的右子树根结点  
	a->rchild = b->lchild; //b的左子树挂在a的右子树上  
	b->lchild = a;

	a->bf = b->bf = 0;
	return b;

}    
AVLNode* LR_Rotate( AVLNode *a ){//LR(先逆后顺)型调整 
	if (a == NULL){
		return NULL;
	}
	AVLNode *b = a->lchild;//b指向a的左子树根结点  
	AVLNode *c = b->rchild;//c指向b的右子树的根节点

	a->lchild = c->rchild;
	b->rchild = c->lchild;

	c->lchild = a;
	c->rchild = b;

	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;

}      
AVLNode* RL_Rotate( AVLNode *a ){//RL(先顺后逆)型调整  
	if (a == NULL){
		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;  
}    

/************************************************************************/
/* 1、找到要插入的位置,同时找到平衡因子为1的结点,因为这个结点修改之后肯定最先变为2
2、从平衡因子不为0的结点到插入结点,开始修改平衡因子
3、找到平衡因子大于等于2的根节点修改即可。
4、修改头结点的指针
*/
/************************************************************************/
void insertAVL(AVLNode **root,int data){
	AVLNode *f, *a, *b, *p, *q;

	AVLNode *s = mallocAVLNode(data);
	//printDataInfo(data);
	//头结点
	if ((*root) == NULL){
		(*root) = s;
		return;
	}
	a=p=(*root) ;     /* a指向离s最近且平衡因子不为0的结点 */

	f=q=NULL ;      /*   f指向a的父结点,q指向p父结点  */ 


	//寻找插入点位置及最小不平衡树的子树  
	while( p != NULL ) {  
		if( p->data == s->data ){
			//AVL中已经存在关键字  
			return;  
		}

		if( p->bf != 0 ){   //寻找最小不平衡子树 
			a = p;  
			f = q;  
		}  
		q = p;  //q指向p父结点 
		if( s->data < p->data ){
			p = p->lchild; 
		}else {
			p = p->rchild;  
		}
	}  

	if( s->data < q->data ){
		q->lchild = s; 
	}  else  {     //将结点*s插入到合适的位置上去  
		q->rchild = s;  
	}

	p = a; //从不为0 的结点开始修改 
	while( p != s ){    //插入结点后修改相应的平衡因子  

		if( s->data < p->data ) { 

			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树的根  
		(*root) = p;  
	else if( f->lchild == a )     //将新子树链到原结点*a的双亲结点上  
		f->lchild = p;  
	else   
		f->rchild = p;  
}

AVLNode* createAVL(){
	int i = 0;
	AVLNode *root = NULL;
	for (i = 0; i< 10;i++){
		insertAVL(&root, keys[i]);
	}
	return root;

}


void inOrderTraverseAVL(AVLNode* root){
	AVLNode* stack[MAX_SIZE];
	int top = -1;

	AVLNode* p = root;
	while(p != NULL || top> -1){
		while ( p!= NULL){
			stack[++top] = p;
			p = p->lchild;
		}

		p = stack[top--];
		printDataInfo(p->data);
		p = p->rchild;
	}

}

void main(){
	AVLNode* root = createAVL();
	inOrderTraverseAVL(root);

}

平衡因子的分析

《平衡二叉排序树》

好基友关于平衡二叉排序树的实现(代码非常美)

AVLTree.h

#ifndef _AVLTREE_H_
#define _AVLTREE_H_

typedef int ElementType;
struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;

AvlTree MakeEmpty(AvlTree T);
Position Find(ElementType X,AvlTree T);
Position FindParent(ElementType X,AvlTree T);
Position FindMin(AvlTree T);
Position FindMax(AvlTree T);
AvlTree Insert(ElementType X,AvlTree T);
AvlTree Delete(ElementType X,AvlTree T);
ElementType Retrieve(Position P);
void PrintAVLTree(AvlTree T);
AvlTree FindInsertParent(ElementType X,AvlTree T);
AvlTree InsertNoRecursion(ElementType X,AvlTree);

#endif

AVLTree.cpp

#include<stdio.h>
#include<stdlib.h>
#include"Common.h"
#include"Error.h"
#include"AVLTree.h"

struct AvlNode
{
	ElementType Element;
	AvlTree Left;
	AvlTree Right;
	int Height;
};

static int Height(Position P)
{
	if(P==NULL)
		return -1;
	else 
		return P->Height;
}

static Position SingleRotateWithLeft(Position K2)
{
	Position K1;
	K1=K2->Left;
	K2->Left=K1->Right;
	K1->Right=K2;

	K2->Height=Max(Height(K2->Left),Height(K2->Right))+1;
	K1->Height=Max(Height(K1->Left),Height(K2->Right))+1;
	return K1;
}
static Position SingleRotateWithRight(Position K2)
{
	Position K1;
	K1=K2->Right;
	K2->Right=K1->Left;
	K1->Left=K2;

	K2->Height=Max(Height(K2->Left),Height(K2->Right))+1;
	K1->Height=Max(Height(K1->Left),Height(K2->Right))+1;
	return K1;
}

static Position DoubleRotateWithLeft(Position K3)
{
	K3->Left=SingleRotateWithRight(K3->Left);
	return SingleRotateWithLeft(K3);
}

static Position DoubleRotateWithRight(Position K3)
{
	K3->Right=SingleRotateWithLeft(K3->Right);
	return SingleRotateWithRight(K3);
}
AvlTree FindInsertParent(ElementType X,AvlTree T)
{
	Position current=T,parent=NULL;
	while(current!=NULL)
	{
		parent=current;
		if(current->Element>X)
			current=current->Left;
		else 
			current=current->Right;
	}
	return parent;
}
AvlTree InsertNoRecursion(ElementType X,AvlTree T)
{
	Position insertParent,insertPP;
	Position insert=(AvlTree)malloc(sizeof(struct AvlNode));
	if(insert==NULL)
		FateErrors("Out of space!");
	insert->Element=X;
	insert->Height=0;
	insert->Left=insert->Right=NULL;
	//树为空
	if(T==NULL)
	{
		T=insert;
	}
	else 
	{
		insertParent=FindInsertParent(X,T);
		insertPP=FindParent(insertParent->Element,T);

	}
	return T;
}
AvlTree Insert(ElementType X,AvlTree T)
{
	if(T==NULL)
	{
		T=(AvlTree)malloc(sizeof(struct AvlNode));
		if(T==NULL)
			FateErrors("Out of space!");
		else
		{
			T->Element=X;
			T->Height=0;
			T->Left=T->Right=NULL;
		}

	}else if(X<T->Element)
	{
		T->Left=Insert(X,T->Left);
		if(Height(T->Left)-Height(T->Right)==2)
			if(X<T->Left->Element)
				T=SingleRotateWithLeft(T);
			else
				T=DoubleRotateWithLeft(T);
	}else if(X>T->Element)
	{
		T->Right=Insert(X,T->Right);
		if(Height(T->Right)-Height(T->Left)==2)
			if(X>T->Right->Element)
				T=SingleRotateWithRight(T);
			else 
				T=DoubleRotateWithRight(T);
	}
	T->Height=Max(Height(T->Left),Height(T->Right))+1;

	return T;
}
Position FindParent(ElementType X,AvlTree T)
{
	Position current=T,parent=NULL;
	while((current!=NULL)&&(current->Element!=X))
	{
		parent=current;
		if(current->Element>X)
			current=current->Left;
		else 
			current=current->Right;
	}
	return parent;

}
Position Find(ElementType X,AvlTree T)
{
	Position current=T;
	while(current!=NULL&¤t->Element!=X)
		if(current->Element>X)
			current=current->Left;
		else 
			current=current->Right;
	return current;
}

Position FindMin(AvlTree T)
{
	Position current=T,parent=NULL;
	while(current!=NULL)
	{
		parent=current;
		current=current->Left;
	}
	return parent;
}
AvlTree Delete(ElementType X,AvlTree T)
{
	Position P=Find(X,T);
	Position parent=FindParent(X,T);
	Position TmpCell;
	if(P==NULL)
		return T;
	if(P->Left==NULL||P->Right==NULL)
	{
		TmpCell=P->Left!=NULL?P->Left:P->Right;
		if(P==parent->Left)
			parent->Left=TmpCell;
		else
			parent->Right=TmpCell;
	}
	else
	{
		TmpCell=FindMin(P->Right);
		T=Delete(TmpCell->Element,T);
		P->Element=TmpCell->Element;
	}
	return T;

}

void PrintAVLTree(AvlTree T)
{
	if(T==NULL)
		return ;
	PrintAVLTree(T->Left);
	printf("%d",T->Element);
	PrintAVLTree(T->Right);
}

参考

http://blog.csdn.net/cheneagle/article/details/4417789

http://blog.csdn.net/jkay_wong/article/details/6905396

http://blog.csdn.net/jkay_wong/article/details/6676488

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/yangzl2008/article/details/10232533
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞