2021/05/11 平衡二叉搜索树的建立 (AVL树)

学了两个星期才把代码实现出来,速度很慢但是我在坚持。
首先要知道,二叉搜索树的特性:

左儿子比父亲节点小;右儿子比父亲节点大。拥有这一特性,我们对二叉树进行查找就会方便很多。

但是在建立二叉搜索树的时候,如果输入序列是从大到小排列的,不加以调整的话,就会出现把数字一个一个往左儿子放的情况;

即退化成线性表。这样显然会耗费更多的时间。(输入序列从小到大同理)所以我们要对二叉搜索树的插入加以调整;

这一过程就叫做平衡化处理;得出来的二叉搜索树也称作平衡二叉搜索树。(AVL树)

AVL树有这样的特性:

1、任一节点的左右子树均为AVL树;

2、根节点左右子树的高度差的绝对值不超过1;(超过1就要进行平衡化处理)
AVL树的结构:

//平衡二叉搜索树

typedef struct node{
	struct node *left;
	struct node *right;
	int date;
	int height;  //高度是它的标配
}AVLTree;

先写一个求较大者的Max函数,方便后面的运算:

int Max(int a,int b) 
{
	if(a>b)
	return a;
	if(b>a)
	return b;
}

我们要有一个求树高的函数:

int GetHeight(AVLTree *T)  //求树高函数 
{	
	int h1,h2,maxh;	
	if(T!=NULL)
	{
		h1=GetHeight(T->left);        //递归求左子树高
		h2=GetHeight(T->right);       //递归求右子树高
		maxh=(Max(h1,h2));	         //取较大者
		return (maxh+1);	
	}	 	
	else 
	return 0;	     //空树树高为0
}

平衡化处理:

首先要知道不平衡的情况有四种:

在这里插入图片描述

我们需要写出解决这四种不平衡的解决方式
左单旋:

AVLTree *turnleft(AVLTree *T)  //左单旋 
{
	AVLTree *B;
	B=T->left;
	T->left=B->right;
	B->right=T;
	T->height=Max(GetHeight(T->left),GetHeight(T->right))+1;  //更新高度 
	B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
	return B;
}

右单旋:

AVLTree *turnright(AVLTree *T)//右单旋 
{
	AVLTree *B;
	B=T->right;
	T->right=B->left;
	B->left=T;
	T->height=Max(GetHeight(T->left),GetHeight(T->right))+1;  //更新高度 
	B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
	return B;
}

左-右旋:

AVLTree *turnleftright(AVLTree *T) //左-右旋 
{
	T->left=turnright(T->left); //先来一次右单旋 
	return turnleft(T);   //再来一次左单旋 
}

右-左旋:

AVLTree *turnrightleft(AVLTree *T)//右-左旋 
{
	T->right=turnleft(T->right);
	return turnright(T);
}

完整代码:

#include<stdio.h>
#include<stdlib.h>
//平衡二叉搜索树 
typedef struct node{
	struct node *left;
	struct node *right;
	int date;
	int height;
}AVLTree;
int Max(int a,int b) 
{
	if(a>b)
	return a;
	if(b>a)
	return b;
}
int GetHeight(AVLTree *T)  //求树高函数 
{	
	int h1,h2,maxh;	
	if(T!=NULL)
	{
		h1=GetHeight(T->left);
		h2=GetHeight(T->right);
		maxh=(Max(h1,h2));	
		return (maxh+1);	
	}	 	
	else
	return 0;	 
}
AVLTree *turnleft(AVLTree *T)  //左单旋 
{
	AVLTree *B;
	B=T->left;
	T->left=B->right;
	B->right=T;
	T->height=Max(GetHeight(T->left),GetHeight(T->right))+1;  //更新高度 
	B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
	return B;
}
AVLTree *turnright(AVLTree *T)//右单旋 
{
	AVLTree *B;
	B=T->right;
	T->right=B->left;
	B->left=T;
	T->height=Max(GetHeight(T->left),GetHeight(T->right))+1;  //更新高度 
	B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
	return B;
}
AVLTree *turnleftright(AVLTree *T) //左-右旋 
{
	T->left=turnright(T->left); //先来一次右单旋 
	return turnleft(T);   //再来一次左单旋 
}
AVLTree *turnrightleft(AVLTree *T)//右-左旋 
{
	T->right=turnleft(T->right);
	return turnright(T);
}
AVLTree *insert(AVLTree *T,int x)  //平衡搜索二叉树插入 
{
	if(T==NULL)
	{
		T=(AVLTree*)malloc(sizeof(AVLTree));
		T->date=x;
		T->left=NULL;
		T->right=NULL;
		T->height=1;
		return T;		
	}	
	if(x<T->date)  //比左儿子小的话 要么左单旋要么左右旋
	{
		T->left=insert(T->left,x); //往左边放
		if(GetHeight(T->left)-GetHeight(T->right)==2)
		{
			if(x<T->left->date)			
			T=turnleft(T);   //左单旋 			
			else
			T=turnleftright(T);  //否则左右旋 
		 } 
	 } 
	 if(x>T->date)
	 {
	 	T->right=insert(T->right,x);
	 	if(GetHeight(T->right)-GetHeight(T->left)==2)
		{
			if(x>T->right->date)
		    T=turnright(T);
			else
			T=turnrightleft(T);
		 } 
	 }
	 T->height=Max(GetHeight(T->left),GetHeight(T->right))+1;  //更新树高 
	 return T;
}
void printftree(AVLTree *T)  //遍历树  先序遍历 
{
	if(T!=NULL)
	{
		printf("%d ",T->date);
		printftree(T->left);
		printftree(T->right);
	}
	return;
}
int main()
{
	int x;
	AVLTree *BT;
	BT=NULL;
	scanf("%d",&x);
	while(x!=-1)
	{
		BT=insert(BT,x);
		scanf("%d",&x);
	}
	printftree(BT);
	return 0;
}

输入1到9

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值