二叉排序树见: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型调整代码*/
//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型调整代码*/
//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型调整代码*/
//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型调整代码*/
//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