AVL树

本文介绍了AVL树的基本概念,包括其作为搜索树的一种保持平衡的方法,四种旋转操作(LL、RR、LR、RL),以及如何通过这些操作确保树的高度保持在最优状态。此外,还提供了一个实现AVL树插入和删除操作的示例代码。

AVL树作为搜索树的衍生其保存了搜索树原有的性质,并且加入了四种需旋转方式使树的的高度维持在一个较优的情况下,以此提升了搜索速度。

起满足:首先是一个搜索树,后通俗的说对其每一个节点的左右子树的高度差不能超过二,否则就要通过旋转操作改变现状。而在实际过程中节点一个一个加入,其左右子树最大差的绝对值在【0,2】内。

四种旋转:

在左子树的左子树上插入新节点使树不平衡(LL){红色为插入点}:


在右子树的右子树上插入新节点使树不平衡(RR){红色为插入点}


在左子树的左子树上插入新节点使树不平衡(LR){白色为插入点}:

这时要先对不平衡节点的下一节点进行RR旋转后对不平衡点进行LL型旋转


在左子树的左子树上插入新节点使树不平衡(RL){白色为插入点}:

这时要先对不平衡节点的下一节点进行LL旋转后对不平衡点进行RR型旋转



而对于旋转后的树高维护只需要在插入和修改后递归过程中进行维护。而且在旋转中除了每次直接参与的两个节点外其余的都是以子树的形式参加所以其高度不会发生改变也就没有维护的必要

在输出时采用中序遍历可以式输出的序列为由小至大的有序数列。

#include<stdio.h>
#include<stdlib.h>
typedef struct node{//节点定义 
	int height;//记录树高 
	int num;//关键字 
	struct node* l;//左儿子 
	struct node* r;//右儿子 
} Node;
Node* Insert(Node* tree,int num);//插入节点 
Node* DeNode(Node* tree,int num);//删除节点 
Node* rrRotate(Node *tree); //RR
Node* llRotate(Node *tree);	//LL 
Node* lrRotate(Node *tree);//RL 
Node* rlRotate(Node *tree); //RL 
int FonPioneer(Node *tree);//找到某节点的中序遍历前驱 
int reHeight(Node* tree);//返回以某节点为根的树的树高 ,若为空返回0 
int Getheight(Node* tree);//获得当前节点树高 ,若没有子树返回1
int Maxheight(int a,int b);//得到最大高度 
void printTree(Node* tree);//输出树(中序遍历) 
void DeTree(Node** ptree);//删除树 
int main()//测试函数(主函数)------------------------------------------------------------------flag 
{
	Node* head=NULL;
	int num;
	while(scanf("%d",&num)==1&&num!=-1)
		head=Insert(head,num);
	printf("树高:%d\n",reHeight(head));
	printTree(head);
	printf("\n");
	head=DeNode(head,20);//删除关键字为20的节点 
	printf("删除关键字为20的节点后树高:%d\n",reHeight(head));  
	printTree(head);
	DeTree(&head);
	return 0; 
}
void printTree(Node* tree)
{
	if(tree==NULL)	return;
	printTree(tree->l);
	printf("%d(%d) ",tree->num,tree->height);//输出节点权值和以该节点为根的树的高度 
	printTree(tree->r);
}
void DeTree(Node** ptree)
{
	if(ptree==NULL||*ptree==NULL)	return;
	DeTree(&((*ptree)->l));
	DeTree(&((*ptree)->r));
	free(*ptree);
	*ptree=NULL;	
}
Node* Insert(Node* tree,int num)
{
	if(tree==NULL)
	{
		tree=(Node *)malloc(sizeof(Node));
		if(tree==NULL)
		{
			printf("插入失败\n");
			return NULL;
		}
		tree->num=num;
		tree->l=NULL;
		tree->r=NULL;	
		tree->height=Getheight(tree);
	}else
	{
		if(num>tree->num)
		{
			tree->r=Insert(tree->r,num);
			tree->height=Getheight(tree);
			if(reHeight(tree->l)-reHeight(tree->r)==-2)
			{
				if(num<tree->r->num)
				{
					tree=rlRotate(tree);
				}else{
					tree=rrRotate(tree);
				}
			}
		}else{
			tree->l=Insert(tree->l,num);
			tree->height=Getheight(tree);
			if(reHeight(tree->l)-reHeight(tree->r)==2)
			{
				if(num>tree->l->num)
				{
					tree=lrRotate(tree);
				}else{
					tree=llRotate(tree);
				}
			}
		}
	}
	return tree;
}
int reHeight(Node* tree)
{
	if(tree==NULL)	return 0;
	else return tree->height; 
} 
int Getheight(Node* tree)
{
	if(tree==NULL)
		return 0;
	else{
		return Maxheight(reHeight(tree->l),reHeight(tree->r))+1;
	}
}
int Maxheight(int a,int b)
{
	return a>b?a:b;
}
Node* DeNode(Node* tree,int num)
{
	if(num==tree->num)//找到删除点 
	{
		if(tree->l==NULL&&tree->r!=NULL)//删除点为叶子 
		{
			Node *deltree=tree;
			tree=tree->r;
			free(deltree);
			deltree=NULL;
		}else if(tree->r==NULL&&tree->l!=NULL)//删除点只有左儿子 
		{
			Node *deltree=tree;
			tree=tree->l;
			free(deltree);
			deltree=NULL;
		}else if(tree->l==NULL&&tree->r==NULL)//删除点只有右儿子 
		{
			free(tree);
			tree=NULL;
		}else{
			int delnum=FonPioneer(tree->l);
			tree->num=delnum;
			tree->l=DeNode(tree->l,delnum);//删除该节点中序遍历前驱 
			tree->height=Getheight(tree);
			if(reHeight(tree->l)-reHeight(tree->r)==-2)
			{
				if(reHeight(tree->r->l)-reHeight(tree->r->r)==1)
				{
					tree=rlRotate(tree);
				}else{
					tree=rrRotate(tree);
				}
			}
		}
	}else if(num>tree->num)//未找到删除点 ,则其删除点一定是该节点子树中一节点,删除可能会改变树高所以应维护树高 
	{
		tree->r=DeNode(tree->r,num);
		tree->height=Getheight(tree); 
		if(reHeight(tree->l)-reHeight(tree->r)==2)
		{
			if(reHeight(tree->l->l)-reHeight(tree->l->r)==-1)
			{
				tree=lrRotate(tree);
			}else{
				tree=llRotate(tree);
			}
		}
	}
	else //未找到删除点 ,则其删除点一定是该节点子树中一节点,删除可能会改变树高所以应维护树高 
	{
		tree->l=DeNode(tree->l,num);
		tree->height=Getheight(tree);
		if(reHeight(tree->l)-reHeight(tree->r)==-2)
		{
			if(reHeight(tree->r->l)-reHeight(tree->r->r)==1)
			{
				tree=rlRotate(tree);
			}else{
				tree=rrRotate(tree);
			}
		}
	}
	return tree;
}
int FonPioneer(Node *tree)
{
	if(tree->r==NULL)
		return tree->num;
	return FonPioneer(tree->r);
}
Node* rrRotate(Node *tree)
{
	Node* newNode=tree->r;
	tree->r=newNode->l;
	newNode->l=tree;
	tree->height=Getheight(tree);
	newNode->height=Getheight(newNode);
	return newNode;
}
Node* llRotate(Node *tree)
{
	Node* newNode=tree->l;
	tree->l=newNode->r;
	newNode->r=tree;
	tree->height=Getheight(tree);
	newNode->height=Getheight(newNode);
	return newNode;
}
Node* lrRotate(Node *tree)
{
	tree->l=rrRotate(tree->l);
	return llRotate(tree);
}
Node* rlRotate(Node *tree)
{
	tree->r=llRotate(tree->r);
	return rrRotate(tree);
}


07-07
AVL是一种自平衡的二叉查找,它确保了的高度始终保持在对数级别,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。这种数据结构以它的发明者G.M. Adelson-Velsky和E.M. Landis的名字命名[^1]。 ### AVL的定义 - **平衡因子**:每个节点都有一个平衡因子,它是该节点左子的高度减去右子的高度。对于AVL来说,所有节点的平衡因子只能是-1, 0或1。 - **空**:如果T是空,则它自然是一个AVL。 - **非空**:若T不是空,则其左右子TL和TR都必须是AVL,并且对于任意节点,|HL - HR| ≤ 1(其中HL和HR分别表示左子和右子的高度)。 ### AVL的操作 当进行插入或删除操作时,可能会破坏AVL的平衡性,这时需要通过旋转来重新恢复平衡: - **单旋转**: - 左单旋(Single Rotate with Left)用于处理左孩子的左子过高。 - 右单旋(Single Rotate with Right)用于处理右孩子的右子过高。 - **双旋转**: - 左右双旋(Double Rotate with Left)用于处理左孩子的右子过高的情况。 - 右左双旋(Double Rotate with Right)用于处理右孩子的左子过高的情况。 这些旋转操作可以保持AVL的性质不变,并且能够快速地调整的结构以维持平衡。 ### AVL的实现 下面是一个简单的C语言代码示例,展示了如何定义AVL的节点以及实现基本的插入操作。这个例子中包含了必要的函数声明和一些核心逻辑。 ```c #include <stdio.h> #include <stdlib.h> // 定义AVL节点结构体 typedef struct AvlNode { int element; struct AvlNode *left; struct AvlNode *right; int height; // 节点的高度 } *AvlTree, *Position; // 获取两个整数中的较大者 int max(int a, int b) { return (a > b) ? a : b; } // 计算给定节点的高度 static int Height(AvlTree T) { if (T == NULL) return -1; // 空节点高度为-1 else return T->height; } // 单旋转 - 左左情况 AvlTree singlerotatewithLeft(AvlTree K2) { Position 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), K2->height) + 1; return K1; // 新根 } // 单旋转 - 右右情况 AvlTree singlerotatewithRight(AvlTree K2) { Position 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->right), K2->height) + 1; return K1; // 新根 } // 双旋转 - 左右情况 AvlTree doublerotatewithLeft(AvlTree K3) { K3->left = singlerotatewithRight(K3->left); return singlerotatewithLeft(K3); } // 双旋转 - 右左情况 AvlTree doublerotatewithRight(AvlTree K3) { K3->right = singlerotatewithLeft(K3->right); return singlerotatewithRight(K3); } // 插入新元素到AVLAvlTree Insert(int x, AvlTree T) { if (T == NULL) { // 如果为空,创建新节点 T = (AvlTree)malloc(sizeof(struct AvlNode)); if (T == NULL) printf("Out of space!!!"); else { T->element = x; T->left = T->right = NULL; T->height = 0; // 新叶节点高度为0 } } 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; } ``` 上述代码提供了AVL的基本框架,包括节点定义、插入操作及必要的旋转方法。实际应用中可能还需要添加更多的功能,如删除节点、查找特定值等。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值