平衡二叉排序树

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





  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1本程序在vc++6.0编译通过并能正常运行。 2主界面 程序已经尽量做到操作简便了,用户只需要根据提示一步步进行操作就行了。 六思考和总结: 这个课程设计的各个基本操作大部分都在我的综合性实验中实现了,所以做这个主要攻克插入和删除这两个算法!其中插入在书本上已经有了,其中的右平衡算法虽然没有给出,但通过给出的左平衡算法很容易就可以写出右平衡算法。所以最终的点就在于删除算法的实现!做的过程中对插入算法进行了非常非常多次的尝试!花了非常多的时间,这其中很多时候是在对程序进行单步调试,运用了VC6。0的众多良好工具,也学到了很多它的许多好的调试手段。 其中删除算法中最难想到的一点是:在用叶子结点代替要删除的非叶子结点后,应该递归的运用删除算法去删除叶子结点!这就是整个算法的核心,其中很强烈得体会到的递归的强大,递归的最高境界(我暂时能看到的境界)! 其它的都没什么了。选做的那两个算法很容易实现的: 1合并两棵平衡二叉排序树:只需遍历其中的一棵,将它的每一个元素插入到另一棵即可。 2拆分两棵平衡二叉排序树:只需以根结点为中心,左子树独立为一棵,右子树独立为一棵,最后将根插入到左子树或右子树即可。 BSTreeEmpty(BSTree T) 初始条件:平衡二叉排序树存在。 操作结果:若T为空平衡二叉排序树,则返回TRUE,否则FALSE. BSTreeDepth(BSTree T) 初始条件:平衡二叉排序树存在。 操作结果:返回T的深度。 LeafNum(BSTree T) 求叶子结点数,非递归中序遍历 NodeNum(BSTree T) 求结点数,非递归中序遍历 DestoryBSTree(BSTree *T) 后序遍历销毁平衡二叉排序树T R_Rotate(BSTree *p) 对以*p为根的平衡二叉排序树作右旋处理,处理之后p指向新的树根结点 即旋转处理之前的左子树的根结点 L_Rotate(BSTree *p) 对以*p为根的平衡二叉排序树作左旋处理,处理之后p指向新的树根结点, 即旋转处理之前的右子树的根结点 LeftBalance(BSTree *T) 对以指针T所指结点为根的平衡二叉排序树作左平衡旋转处理, 本算法结束时,指针T指向新的根结点 RightBalance(BSTree *T) 对以指针T所指结点为根的平衡二叉排序树作右平衡旋转处理, 本算法结束时,指针T指向新的根结点 Insert_AVL(BSTree *T, TElemType e, int *taller) 若在平衡二叉排序树T中不存在和e有相同的关键字的结点, 则插入一个数据元素为e的新结点,并返回OK,否则返回ERROR. 若因插入而使二叉排序树失去平衡,则作平衡旋转处理 布尔变量taller反映T长高与否 InOrderTraverse(BSTree T) 递归中序遍历输出平衡二叉排序树 SearchBST(BSTree T, TElemType e, BSTree *f, BSTree *p) 在根指针T所指的平衡二叉排序树中递归的查找其元素值等于e的数据元素, 若查找成功,则指针p指向该数据元素结点,并返回TRUE,否则指针p 指向查找路径上访问的最后一个结点并返回FALSE,指针f指向T的双亲, 其初始调用值为NULL Delete_AVL(BSTree *T, TElemType e, int *shorter) 在平衡二叉排序树中删除元素值为e的结点,成功返回OK,失败返回ERROR PrintBSTree_GList(BSTree T) 以广义表形式打印出来 PrintBSTree_AoList(BSTree T, int length) 以凹入表形式打印,length初始值为0 Combine_Two_AVL(BSTree *T1, BSTree T2) 合并两棵平衡二叉排序树 Split_AVL(BSTree T, BSTree *T1, BSTree *T2) 拆分两棵平衡二叉树 } (2)存储结构的定义: typedef struct BSTNode { TElemType data; int bf; //结点的平衡因子 struct BSTNode *lchild, *rchild;//左.右孩子指针 }BSTNode, *BSTree;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值