第9章 平衡二叉排序树(AVL)(算法实现)

前情回顾:第9章 平衡二叉排序树(AVL)(手工分析):点击这里

考虑使用序列 {1, 2, 3, 4, 5} 构建二叉查找树,会得到下图所示的二叉查找树:

BST退化成一个只包含右子树的链表,对这棵树中结点进行查找的复杂度就会达到O(n),起不到使用二叉查找树来进行数据查询优化的目的。

可以看到,BST的优劣取决于它是否为一个平衡的二叉树。

BST有关算法的主要功能是努力使它保持平衡,BST算法有AVL树、红黑树、Splay树、Treap树、SBT树等。

【定义】

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

平衡二叉树,或者是空树,或者是满足下列性质的二叉树。

  1. 左子树和右子树深度之差的绝对值不大于1;
  2. 左子树和右子树也都是平衡二叉树。

平衡因子(Balance Factor) :二叉树上结点的左子树的深度减去其右子树深度称为该结点的平衡因子。

因此,平衡二叉树上每个结点的平衡因子只可能是-1、0和1,否则,只要有一个结点的平衡因子的绝对值大于1, 该二叉树就不是平衡二叉树。

/* 平衡二叉树(AVL树)存储表示 */
typedef int KeyType;			//关键字类型 
typedef struct
{
	KeyType key;				//关键字域
	//float weight;				//其他域(此处可设为权重) 
}ElemType;

typedef struct BBSTNode					
{
	ElemType data;
	int bf;								//结点的平衡因子 
	struct BBSTNode* lchild;
	struct BBSTNode* rchild;
}BBSTNode;								//平衡二叉排序树结点 
typedef BBSTNode* BBSTree;				//指向平衡二叉排序树结点的指针

【实现】

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

/* 宏定义 */
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a) < (b))
#define RT(a,b) ((a) > (b))
#define LH  1							//左子树高 
#define EH  0							//等高 
#define RH -1							//右子树高
 
#define	TRUE		1			//真 
#define	FALSE		0			//假
#define	OK			1			//通过
#define	ERROR		0			//错误
typedef int Status;

/* 平衡二叉树(AVL树)存储表示 */
typedef int KeyType;			//关键字类型 
typedef struct
{
	KeyType key;				//关键字域
	//float weight;				//其他域(此处可设为权重) 
}ElemType;

typedef struct BBSTNode					
{
	ElemType data;
	int bf;								//结点的平衡因子 
	struct BBSTNode* lchild;
	struct BBSTNode* rchild;
}BBSTNode;								//平衡二叉排序树结点 
typedef BBSTNode* BBSTree;				//指向平衡二叉排序树结点的指针

//算法9.9:右旋。
void R_Rotate(BBSTree *p)
{
	BBSTree lc;
	
	lc = (*p)->lchild;
	(*p)->lchild = lc->rchild;
	lc->rchild = *p;
	*p = lc;	
}


//算法9.10:左旋。
void L_Rotate(BBSTree *p)
{
	BBSTree rc;
	
	rc = (*p)->rchild;
	(*p)->rchild = rc->lchild;
	rc->lchild = *p;
	*p = rc;	
}

//右平衡处理。
void RightBalance(BBSTree *BBST)
{
	BBSTree rc, ld;
	
	rc = (*BBST)->rchild;
	
	switch(rc->bf)
	{
		case RH:					//新结点插入在*BBST右孩子的右子树上
			(*BBST)->bf = rc->bf = EH;
			L_Rotate(BBST);			
			break;

		case LH: 					//新结点插入在*BBST右孩子的左子树上
			ld = rc->lchild;			
			switch(ld->bf)
			{
				case LH:
					(*BBST)->bf = EH;
					rc->bf = RH;
					break;
				case EH:
					(*BBST)->bf = rc->bf = EH;
					break;
				case RH:
					(*BBST)->bf = LH;
					rc->bf = EH;
					break;
			}			
			ld->bf = EH;
			R_Rotate(&(*BBST)->rchild);
			L_Rotate(BBST);
			break;
	}
}

//算法9.12:左平衡处理。
void LeftBalance(BBSTree *BBST)
{
	BBSTree lc, rd;
	
	lc = (*BBST)->lchild;
	
	switch(lc->bf)
	{
		case LH:					//新结点插入在*BBST左孩子的左子树上 
			(*BBST)->bf = lc->bf = EH;
			R_Rotate(BBST);
			break;
		
		case RH:					//新结点插入在*BBST左孩子的右子树上
			rd = lc->rchild;			
			switch(rd->bf)
			{
				case LH:
					(*BBST)->bf = RH;
					lc->bf = EH;
					break;
				case EH:
					(*BBST)->bf = lc->bf = EH;
					break;
				case RH:
					(*BBST)->bf = EH;
					lc->bf = LH;
					break;
			}			
			rd->bf = EH;
			L_Rotate(&(*BBST)->lchild);
			R_Rotate(BBST);
			break;
	}
}

//1. 算法9.11:插入。
//进行了插入操作,则返回1,否则返回0。
//插入新结点,树“长高”,置taller为false 
Status InsertAVL(BBSTree *BBST, ElemType e, bool *taller)
{
	if(!(*BBST))
	{
		*BBST = (BBSTree)malloc(sizeof(BBSTNode));
		(*BBST)->data = e;
		(*BBST)->lchild = (*BBST)->rchild = NULL;
		(*BBST)->bf = EH;
		*taller = true;
	}
	else
	{
		if(EQ(e.key, (*BBST)->data.key))	//若树中已存在和e有相同关键字的结点,则不再插入 
		{
			*taller = false;
			return 0;
		}
		else if(LT(e.key, (*BBST)->data.key))	//搜寻左子树 
		{
			if(!InsertAVL(&(*BBST)->lchild, e, taller))
				return 0;						//未插入

			if(*taller)					//已插入到*BBST的左子树中且左子树“长高”
			{
				switch((*BBST)->bf)
				{
					case LH:			//插入前左子树高于右子树,需做左平衡处理 
						LeftBalance(BBST);
						*taller = false;
						break;
					case EH:			//插入前左子树等高于右子树,现左子树“增高” 
						(*BBST)->bf = LH;
						*taller = true;
						break; 
					case RH:			//插入前右子树高于左子树,现左右子树等高 
						(*BBST)->bf = EH;
						*taller = false;
						break;
				}
			}
		}
		else							//搜寻右子树 
		{
			if(!InsertAVL(&(*BBST)->rchild, e, taller))
				return 0;				//未插入 		

			if(*taller)					//已插入到*BBST的左子树中且左子树“长高”
			{
				switch((*BBST)->bf)
				{
					case LH:			//插入前左子树高于右子树,现左右子树等高 
						(*BBST)->bf = EH;
						*taller = false;
						break;
					case EH:			//插入前左右子树等高,现右子树“增高” 
						(*BBST)->bf = RH;
						*taller = true;
						break; 
					case RH:			//插入前右子树高于左子树,需做右平衡处理 
						RightBalance(BBST);
						*taller = false;
						break;
				}
			}
		}
	}
	
	return 1;
}

//2.创建AVL树。
Status CreateAVL(BBSTree *BBST)
{
	int n;
	ElemType e;
	printf("请输入元素个数:");
	scanf("%d", &n);
	printf("请依次输入元素的关键字:");
		
	*BBST = NULL;
	bool t = false;
	
	if(n)
	{
		for(int i = 1; i <= n; i++)
		{
			scanf("%d", &e.key);
			InsertAVL(BBST, e, &t);
		}	
	}
	
	return OK;
}

//3.查找,返回指向key的指针,若不存在返回MULL。 
BBSTree SearchAVL(BBSTree BBST, KeyType key)
{
	if(!BBST || EQ(key, BBST->data.key))
		return BBST;
	else if(LT(key, BBST->data.key))
		return SearchAVL(BBST->lchild, key);
	else
		return SearchAVL(BBST->rchild, key);
}

//4.删除。
Status DeleteAVL(BBSTree *BBST, ElemType e, BBSTree f, BBSTree p, bool *taller, int mark)
{//p指向当前结点,f指向p的父结点,初始化为空,*taller初始化为FALSE,mark代表f与p的关系,初始化为0 
	BBSTree r;
	ElemType tmp;
	 
	if(!p)
		return ERROR;
	else
	{
		if(LT(e.key, p->data.key))				//关键字较小,搜寻左子树
		{			
			if(!DeleteAVL(BBST, e, p, p->lchild, taller, 0))
				return ERROR;
			
			if(*taller)
			{
				switch(p->bf)
				{
					case LH:
						p->bf = EH;
						*taller = true;
						break;
					case EH:
						p->bf = RH;
						*taller = false;
						break;
					case RH:
						if(!f)
							RightBalance(BBST);
						else
							RightBalance(&(f->lchild));
						*taller = true;
						break;				
				}			
			}
		}			
		else if(RT(e.key, p->data.key))			//关键字较大,搜寻右子树
		{	
			if(!DeleteAVL(BBST, e, p, p->rchild, taller, 1))
				return ERROR;	
						
			if(*taller)
			{
				switch(p->bf)
				{
					case LH:
						if(!f)
							LeftBalance(BBST);
						else
							LeftBalance(&(f->rchild));
						*taller = true;
						break;
					case EH:
						p->bf = LH;
						*taller = false;
						break;
					case RH:
						p->bf = EH;
						*taller = true;
						break;				
				}
			}
		}
		else												//找到关键字 
		{			
			if(p->lchild!=NULL && p->rchild==NULL)			//只有左子树
			{
				if(!f)										//根结点 
					*BBST = p->lchild;			
				else
				{
					if(mark==0)
						f->lchild = p->lchild;
					else
						f->rchild = p->lchild;
				}
				
				free(p);
				p = NULL;
				
				*taller = true;	
			}
			else if(p->lchild==NULL && p->rchild!=NULL)		//只有右子树
			{
				if(!f)										//根结点 
					*BBST = p->rchild;			
				else
				{
					if(mark==0)
						f->lchild = p->rchild;
					else
						f->rchild = p->rchild;
				}	
				
				free(p);
				p = NULL;
				
				*taller = true;			
			}
			else if(p->lchild==NULL && p->rchild==NULL)		//左右子树均为空
			{
				if(!f)										//根结点 
					*BBST = NULL;			
				else
				{
					if(mark==0)
						f->lchild = NULL;
					else
						f->rchild = NULL;
				}	
				
				free(p);
				p = NULL;
				
				*taller = true;
			} 
			else											//左右子树均不空
			{
				r = p->lchild;
			
				while(r->rchild)
					r = r->rchild;
				
				tmp = r->data;
				
				*taller = false;
				if(!f)
					DeleteAVL(BBST, tmp, NULL, p, taller, mark);
				else
				{
					if(mark==0)
						DeleteAVL(&(f->lchild), tmp, NULL, p, taller, mark);
					else								
						DeleteAVL(&(f->rchild), tmp, NULL, p, taller, mark);				
				}
				p->data = tmp;
			} 
		}
	
		return OK;
	}
}

//5.中序遍历。
void InOrderTraverse_AVL(BBSTree BBST)
{
	if(BBST)
	{
		InOrderTraverse_AVL(BBST->lchild);
		printf("%d ", BBST->data.key);
		InOrderTraverse_AVL(BBST->rchild);	
	}
}

//6.求树的深度。
int AVLDepth(BBSTree BBST)
{
	int LD, RD;
	
	if(BBST==NULL)
		return 0;								//空树深度为0 
	else
	{
		LD = AVLDepth(BBST->lchild);			//求左子树深度 
		RD = AVLDepth(BBST->rchild);			//求右子树深度 
	
		return (LD>=RD?LD:RD)+1;
	}
}

//7.打印树。
void PrintAVLTree(BBSTree BBST)
{
	int row, col;
	int i, j, m, l, r;
	BBSTNode a[100][100] = {};
	
	if(BBST)
	{
		row = AVLDepth(BBST);					//总行数 
		col = pow(2, row) - 1;					//总列数 
		
		for(i = 1; i <= row-1; i++)
		{
			for(j = 1; j <= pow(2, i-1); j++)
			{
				m = (2*j-1)*pow(2, row-i);		//当前行结点相对位序 
				l = (4*j-3)*pow(2, row-i-1);	//下一行结点相对位序 
				r = (4*j-1)*pow(2, row-i-1);
				
				if(i==1)						//初始化 
					a[i][m] = *BBST;
				
				if(a[i][m].lchild)				//下一行 
					a[i+1][l] = *(a[i][m].lchild);
					
				if(a[i][m].rchild)				//下一行 
					a[i+1][r] = *(a[i][m].rchild);
			} 
		}
		
		for(i = 1; i <= row; i++)
		{
			for(j = 1; j <= col; j++)
			{
				if(a[i][j].data.key)
					printf("%2d", a[i][j].data.key);
				else
					printf("  ");
			}
			printf("\n");
		}	
	}
}

int main(int argc, char *argv[])
{
	BBSTree BBST;
	
	CreateAVL(&BBST);
	PrintAVLTree(BBST);
	printf("\n\n");
	
	printf("中序序列为:"); 
	InOrderTraverse_AVL(BBST);
	printf("\n\n");

	KeyType key;
	printf("请输入查找元素的关键字:");
	scanf("%d", &key);
	SearchAVL(BBST, key)==NULL ? printf("不在平衡二叉树中!\n\n") : printf("在平衡二叉树中!\n\n");

	BBSTree f = NULL, p = BBST;
	bool taller = false;
	ElemType e;
	printf("请输入删除元素的关键字:");
	scanf("%d", &e.key); 
	DeleteAVL(&BBST, e, f, p, &taller, 0);	
	printf("删除关键字后的平衡二叉树为:\n");
	PrintAVLTree(BBST);
	printf("\n\n");
	
	return 0;
}

运行结果:

发布了674 篇原创文章 · 获赞 103 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/103640187