AVL平衡二叉树 c语言实现代码

说明

在阅读下列代码时,为了保障能够轻松理解,请务必对指针和二叉排序树数据结构以及平衡原理有较深的了解
思路:
在每次插入结点时,去检查平衡性是否遭到破坏,若是,则进行平衡调整,平衡调整分两种情况,左子树高于右子树(右旋)和 右子树高于左子树(左旋),同时,每一种情况又存在两种情景,可直接旋转和两次旋转
(左旋和右旋代码具有对称性,各位看官好好体会理解)

定义

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

//状态
typedef int status;
#define TRUE 1
#define FLASE 0

//平衡因子
#define EH 0 //等高
#define LH 1 //左子树高
#define RH -1 //右子树高


//定义一个结构体
typedef struct BiTNode
{
	int data; //数据
	int bf; //平衡因子
	struct BiTNode *lchild,*rchild; //左子树和右子树
}BiTNode,*BiTree;

//中序遍历
void InOrderTraverse(BiTree b){
	if(!b){
		return;
	}
	InOrderTraverse(b->lchild);
	printf("%d,",b->data);
	InOrderTraverse(b->rchild);
}

左旋平衡调整

//左旋
void L_Rotate(BiTree *p){
	printf("%d结点进行左旋\n",(*p)->data);
	//定义当前结点的右子树
	BiTree R;
	//赋值
	R = (*p)->rchild;
	//将R的左子树赋值给当前节点p的右子树
	(*p)->rchild = R->lchild;
	//将R的左子树指向当前结点p
	R->lchild = (*p);
	printf("%d结点左旋完毕:",(*p)->data);
	*p = R;
	InOrderTraverse(*p);
	printf("\n");
}

//左旋平衡处理 若b结点和左子树结点平衡因子正负相反 需要进行两次旋转
void LeftBanlance(BiTree *b){
	BiTree r,rl;
	r = (*b)->rchild;
	//判断b的右子树的平衡因子 当和b为正负相反需要进行两次旋转
	switch(r->bf){
		//左子树高
		case LH:
			rl = r->lchild;
			printf("%d结点的左子树%d结点的平衡因子%d\n",(*b)->data,r->data,r->bf);
			//对r的左子树平衡因子进行判断
			switch(rl->bf){
				//调整平衡时 改变b结点和右子树结点的平衡因子 有以下三种情景
				case LH:
					(*b)->bf=LH;
					r->bf = EH;
					break;
				case RH:
					(*b)->bf=EH;
					r->bf=RH;
					break;
				case EH:
					//这种情况在我理解下应该是不会发生
					(*b)->bf=r->bf=EH;
					break;
			}
			rl->bf=EH;
			R_Rotate(&(*b)->rchild); //先对b的右子树进行右旋
			L_Rotate(b); //再对当前结点b进行左旋
			break;
		//右子树高
		case RH:
			(*b)->bf=r->bf=LH;
			//直接左旋
			L_Rotate(b);
			break;
	}
}

右旋平衡调整

//右旋
void R_Rotate(BiTree *p){
	printf("%d结点进行右旋\n",(*p)->data);
	//当前结点的左子树
	BiTree L;
	//赋值
	L = (*p)->lchild;
	//将L的右子树赋值给当前结点p的左子树
	(*p)->lchild = L->rchild;
	//将左子树的右子树指向当前结点p
	L->rchild = (*p);
	printf("%d结点右旋完毕:",(*p)->data);
	//*p拿到的是指针地址 根据点重新指向L 完成右旋
	*p = L;	
	InOrderTraverse(*p);
	printf("\n");
}

//右旋平衡处理 若b结点和左子树结点平衡因子正负相反 需要进行两次旋转
void RightBanlance(BiTree *b){
	BiTree L,Lr;
	L = (*b)->lchild;
	//判断左子树的平衡因子
	switch(L->bf){
		//右子树高 符号为负
		case RH:
			Lr = L->rchild;
			printf("%d结点的左子树%d结点的平衡因子%d\n",(*b)->data,L->data,L->bf);
			//对r的左子树平衡因子进行判断
			switch(Lr->bf){
				case LH:
					(*b)->bf=RH;
					L->bf = EH;
					break;
				case RH:
					(*b)->bf=EH;
					L->bf=LH;
					break;
				case EH:
					//这种情况在我的理解下应该是不会发生 欢迎补充
					(*b)->bf=L->bf=EH;
					break;
			}
			Lr->bf=EH;
			L_Rotate(&(*b)->lchild); //先对b的左子树进行左旋
			R_Rotate(b); //再对当前结点b进行右旋
			break;
		//左子树高 符号为正
		case LH:
			(*b)->bf=L->bf=RH;
			//直接右旋
			R_Rotate(b);
			break;
	}
}


主要函数

//主函数
status InsertAVL(BiTree *b,int data,status *taller) //taller 表示树的高度是否增加
{
	//如果当前结点不存在
	if(!*b){
		printf("%d开辟空间\n",data);
		//则开辟内存
		*b = (BiTree) malloc(sizeof(BiTNode));
		//赋值
		(*b)->data = data;
		//当前结点左子树右子树赋值为NULL
		(*b)->lchild=(*b)->rchild=NULL;
		//当前结点的平衡因子为等高
		(*b)->bf=EH;
		//插入当前结点表示树的高度增加
		*taller = TRUE;
	}
	else
	{
		//如果值相等不进行插入
		if(data==(*b)->data){
			printf("%d已经存在不进行插入\n",data);
			return FLASE;
		}
		//如果小于当前结点的值进入左子树
		if(data<(*b)->data){
			printf("%d进入%d结点的左子树\n",data,(*b)->data);
			//进入左子树进行递归添加
			if(!InsertAVL(&(*b)->lchild,data,taller) ){
				printf("插入失败\n");
				//插入失败
				return FLASE;
			}
			//如果树的高度变高
			if(*taller){
				//判断当前结点平衡因子
				switch((*b)->bf){
					//原本左子树高,现在左子树增高
					case LH:
						//进行右旋平衡处理
						RightBanlance(b);
						*taller = FLASE;
						break;
					//原本右子树高,现在左子树增高
					case RH:
						(*b)->bf = EH;
						*taller = FLASE;
						break;
					//原本左右子树等高,现在左子树增高
					case EH:
						(*b)->bf = LH;
						*taller = TRUE;
						break;
				}
				printf("%d结点平衡因子:%d\n",(*b)->data,(*b)->bf);
			}
		}
		//如果大于当前结点的值进入右子树
		else
		{
			printf("%d进入%d结点的右子树\n",data,(*b)->data);
			//进入右子树进行递归添加
			if(!InsertAVL(&(*b)->rchild,data,taller) ){
				//插入失败
				return FLASE;
			}
			//如果树的高度变高
			if(*taller){
				//判断当前结点平衡因子
				switch((*b)->bf){
					//原本左子树高,现在右子树增高
					case LH:
						(*b)->bf = EH;
						*taller = FLASE;
						break;
					//原本右子树高,现在右子树增高
					case RH:
						//进行左旋平衡处理
						LeftBanlance(b);
						*taller = TRUE;
						break;
					//原本左右子树等高,现在右子树增高
					case EH:
						(*b)->bf = RH;
						*taller = TRUE;
						break;
				}
				printf("%d结点平衡因子:%d\n",(*b)->data,(*b)->bf);
			}
		}
	}
	printf("%d结点执行完毕\n========================================================\n",(*b)->data);
	return TRUE;
}


//main函数
void main(){
	//printf("%d",malloc(sizeof(BiTNode)));
	//BiTree b = (BiTree)malloc(sizeof(BiTNode));
	int a[20]={14,45,21,20,99,35,3,1,7,25,43,75,34,63,8123,52,28,1234,64,234};
	BiTree b = NULL;
	status taller;
	for(int i=0;i<20;i++){
		InsertAVL(&b,a[i],&taller);
	}
	InOrderTraverse(b);
}


执行结果

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值