【数据结构】基于树的查找法——平衡二叉排序树(C语言)

二叉排序树见:https://blog.csdn.net/weixin_51450101/article/details/123172688?spm=1001.2014.3001.5501

1. 平衡二叉排序树

平衡二叉排序树又称AVL树。一棵平衡二叉排序树或者是空树,或者是具有下列性质的二叉排序树:
① 左子树与右子树的高度之差的绝对值小于等于1;
② 左子树和右子树也是平衡二叉排序树。
引入平衡二叉排序树的目的是为了提高查找效率。
平衡因子:结点的左子树深度与右子树深度之差。显然对一棵平衡二叉排序树而言,其所有结点的平衡因子只能是-1、0或1。当在一个平衡二叉排序树上插入一个结点时,有可能导致失衡,即出现绝对值大于1的平衡因子,如2和-2。
平衡及失衡类型定义

typedef int DataType;
/*平衡二叉排序树的类型定义*/
typedef struct node {
    
    
	DataType data;
	int bf;			//结点的平衡因子
	struct node* lchild, * rchild;
}AVLNode, * AVLTree;

2. 失衡类型及调整方法

2.1 LL型
假设最低层失衡结点为A,在结点A的左子树的左子树插入新结点S导致失衡。由A和B的平衡因子容易容易推知,BL、BR以及AR的深度相同。为了恢复平衡并保持二叉排序树特性,可按下图方式进行调整:
LL型

/*LL型调整代码*/
//1 旋转结点实现平衡
A->lchild = B->rchild;
B->rchild = A;
//2 调整平衡因子
A->bf = 0;	B->bf = 0;
//3 将当前调整完的子树接到原树上
if (FA == NULL)			//FA为A原来的父指针
	*avlt = B;
else if (A == FA->lchild)	FA->lchild = B;
else	FA->rchild = B;

2. LR型
假设最低层失衡结点为A,在结点A的左子树的右子树插入新结点S导致失衡。这里假设在CL下插入S,由A、B、C的平衡因子推知,CL与CR深度相同,BL与AR深度相同,且BL、AR比CL、CR的深度大1。为了恢复平衡并保持二叉排序树特性,可按下图方式进行调整:
LR型

/*LR型调整代码*/
//1 旋转结点实现平衡
C = B->rchild;
B->rchild = C->lchild;
A->lchild = C->rchild;
C->lchild = B;
C->rchild = A;
//2 调整平衡因子
if (S->data < C->data) {
    
    
	A->bf = -1;
	B->bf = 0;
	C->bf = 0;
}
else if (S->data > C->data) {
    
    
	A->bf = 0;
	B->bf = 1;
	C->bf = 0;
}
else {
    
    
	A->bf = 0;
	B->bf = 0;
}
//3 将当前调整完的子树接到原树上
if (FA == NULL)		//FA为A原来的父指针
	*avlt = C;
else if (A == FA->lchild)
	FA->lchild = C;
else
	FA->rchild = C;
}

3. RR型
RR型和LL型对称。假设最低层失衡结点为A,在结点A的右子树的右子树插入新结点S导致失衡。由A和B的平衡因子容易容易推知,BL、BR以及AL的深度相同。为了恢复平衡并保持二叉排序树特性,可按下图方式进行调整:
RR型

/*RR型调整代码*/
//1 旋转结点实现平衡
A->rchild = B->lchild;
B->lchild = A;
//2 调整平衡因子
A->bf = 0; B->bf = 0;
//3 将当前调整完的子树接到原树上
if (FA == NULL)		//FA为A原来的父指针
	*avlt = B;
else if (A == FA->lchild)
	FA->lchild = B;
else
	FA->rchild = B;
} 

4. RL型
RL型和LR型对称。假设最低层失衡结点为A,在结点A的右子树的左子树插入新结点S导致失衡。这里假设在CR下插入S,由A、B、C的平衡因子推知,CL与CR深度相同,AL与BR深度相同,且AL、BR比CL、CR的深度大1。为了恢复平衡并保持二叉排序树特性,可按下图方式进行调整:
RL型

/*RL型调整代码*/
//1 旋转结点实现平衡
C = B->lchild;
B->lchild = C->rchild;
A->rchild = C->lchild;
C->lchild = A;
C->rchild = B;
//2 调整平衡因子
if (S->data < C->data) {
    
    
	A->bf = 0;
	B->bf = -1;
	C->bf = 0;
}
else if (S->data > C->data) {
    
    
	A->bf = 1;
	B->bf = 0;
	C->bf = 0;
}
else {
    
    
	A->bf = 0;
	B->bf = 0;
}
//3 将当前调整完的子树接到原树上
if (FA == NULL)		//FA为A原来的父指针
	*avlt = C;
else if (A == FA->lchild)
	FA->lchild = C;
else
	FA->rchild = C;
}

3. 完整实现代码及运行结果

/*平衡二叉排序树*/
# include<stdio.h>
# include<malloc.h>

typedef int DataType;

/*平衡二叉排序树的类型定义*/
typedef struct node {
    
    
	DataType data;
	int bf;							//结点的平衡因子
	struct node* lchild, * rchild;
}AVLNode, * AVLTree;

/*平衡二叉排序树的插入算法*/
void Ins_AVLtree(AVLTree* avlt, DataType data) {
    
    
	AVLNode* S, * A = *avlt, * FA = NULL, * p = *avlt, * fp = NULL, * B, * C;
	S = (AVLTree)malloc(sizeof(AVLNode));
	S->data = data;
	S->lchild = S->rchild = NULL;
	S->bf = 0;
	if (*avlt == NULL) {
    
    				//平衡二叉树为空直接插入
		*avlt = S;
		return;
	}
	/*查找插入位置*/
	else {
    
    								//首先查找S的插入位置fp,同时记录距S的插入位置最近且平衡因子不等于0的结点A,该结点可能为失衡结点
		while (p != NULL) {
    
    
			if (p->bf != 0) {
    
    
				A = p;
				FA = fp;
			}
			fp = p;
			if (data < p->data)
				p = p->lchild;
			else
				p = p->rchild;
		}
	}
	/*插入S*/
	if (data < fp->data)
		fp->lchild = S;
	else
		fp->rchild = S;
	/*确定结点B并修改A的平衡因子*/
	if (data < A->data) {
    
    
		B = A->lchild;
		A->bf = A->bf + 1;
	}
	else {
    
    
		B = A->rchild;
		A->bf = A->bf - 1;
	}
	/*修改B到S路径上各结点的平衡因子(原值均为0)*/
	p = B;
	while (p != S) {
    
    
		if (data < p->data) {
    
    
			p->bf = 1;
			p = p->lchild;
		}
		else {
    
    
			p->bf = -1;
			p = p->rchild;
		}
	}
	/*判断失衡类型并做相应处理*/
	if (A->bf == 2 && B->bf == 1) {
    
    			//LL型
		A->lchild = B->rchild;
		B->rchild = A;
		A->bf = 0;
		B->bf = 0;
		if (FA == NULL)
			*avlt = B;
		else if (A == FA->lchild)
			FA->lchild = B;
		else
			FA->rchild = B;
	}
	else if (A->bf == 2 && B->bf == -1) {
    
    	//LR型
		C = B->rchild;
		B->rchild = C->lchild;
		A->lchild = C->rchild;
		C->lchild = B;
		C->rchild = A;
		if (S->data < C->data) {
    
    
			A->bf = -1;
			B->bf = 0;
			C->bf = 0;
		}
		else if (S->data > C->data) {
    
    
			A->bf = 0;
			B->bf = 1;
			C->bf = 0;
		}
		else {
    
    
			A->bf = 0;
			B->bf = 0;
		}
		if (FA == NULL)
			*avlt = C;
		else if (A == FA->lchild)
			FA->lchild = C;
		else
			FA->rchild = C;
	}
	else if (A->bf == -2 && B->bf == 1) {
    
    	//RL型
		C = B->lchild;
		B->lchild = C->rchild;
		A->rchild = C->lchild;
		C->lchild = A;
		C->rchild = B;
		if (S->data < C->data) {
    
    
			A->bf = 0;
			B->bf = -1;
			C->bf = 0;
		}
		else if (S->data > C->data) {
    
    
			A->bf = 1;
			B->bf = 0;
			C->bf = 0;
		}
		else {
    
    
			A->bf = 0;
			B->bf = 0;
		}
		if (FA == NULL)
			*avlt = C;
		else if (A == FA->lchild)
			FA->lchild = C;
		else
			FA->rchild = C;
	}
	else if (A->bf == -2 && B->bf == -1) {
    
    	//RR型
		A->rchild = B->lchild;
		B->lchild = A;
		A->bf = 0;
		B->bf = 0;
		if (FA == NULL)
			*avlt = B;
		else if (A == FA->lchild)
			FA->lchild = B;
		else
			FA->rchild = B;
	}
}

/*创建平衡二叉排序树*/
void CreatAVLT(AVLTree* avlt) {
    
    
	DataType data;
	*avlt = NULL;
	scanf("%d", &data);
	while (data != 0) {
    
    
		Ins_AVLtree(avlt, data);
		scanf("%d", &data);
	}
}

/*中序遍历输出平衡排序二叉树*/
void InOrder(AVLTree avlt) {
    
    
	if (avlt != NULL) {
    
    
		InOrder(avlt->lchild);
		printf("%d(%d) ", avlt->data, avlt->bf);
		InOrder(avlt->rchild);
	}
}

int main() {
    
    
	AVLTree avlt;
	CreatAVLT(&avlt);
	printf("中序遍历输出:");
	InOrder(avlt);
	return 0;
}

运行结果
运行结果

输出结果括号内值为相应结点的平衡因子。
运行示例所对应的平衡二叉排序树见下图:
运行用例
参考:耿国华《数据结构——用C语言描述(第二版)》

更多数据结构内容关注我的《数据结构》专栏https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482

猜你喜欢

转载自blog.csdn.net/weixin_51450101/article/details/123372250