树与二叉树(三)

1.平衡二叉树(AVL树)的定义

AVL树是一种自平衡二叉查找树树中任何结点的两个子树高度之差的绝对值不超过1,也成为高度平衡树,左子树与右子树的高度之差成为该结点的平衡因子
只要能随时保证每个结点平衡因子的绝对值不超过1,AVL的高度就能始终保持O(logn)级别
(1)存储结构

struct node{
	int data;
	int height;    //当前子树高度
	node *lchild;
	node *rchild;
}

(2)创建新结点

node* newNode(int x){
	node *root=new node;
	root->lchild=NULL;
	root->rchild=NULL;
	root->data=x;
	root->height=1;
	return root;
}

(3)获取以root为根结点的子树的高度

int getHeight(node *root){
	if(root==NULL)
		return 0;
	return root->height;
}

(4)计算结点root的平衡因子

int getBalanceFactor(node *root){
	return getHeight(root->lchild)-getHeight(root->rchild);
}

(5)更新结点的高度(高度是从下往上计算)

void updateHeight(node *root){
	root->height=max(getHeight(root->lchild),getHeight(root->rchild))+1;
}

2.平衡二叉树的操作

(1)查找
由于AVL树是一颗二叉查找树,所以查找操作和二叉查找树一摸一样。

void search(node *root,int x){
	if(root==NULL){
		printf("failed.\n");
		return;
	}
	if(root->data==x)
		printf("%d\n",root->data);
	else if(x<root->data)
		search(root->lchild,x);
	else
		search(root->rchild,x);
}

(2)旋转
1.左旋
假设有如下一颗AVL树,根结点为A,使其右子结点B为新的根结点,并保证调整后的树仍然是一颗AVL树,这个过程叫做左旋
调整过程:使B的左子树成为A的右子树,A成为B的左子树,再将B设为根结点。
在这里插入图片描述
代码:

void L(node* &root){
	node *t=root->rchild;    //结点B
	root->rchild=t->lchild;
	t->lchild=root;
	updateHeight(root);    //更新A、B结点的高度
	updateHeight(t);
	root=t;
}

2.右旋
相应的与左旋对应的过程称为右旋
在这里插入图片描述

代码:

void R(node* &root){
	node *t=root->lchild;
	root->lchild=t->rchild;
	t->rchild=root;
	updateHeight(root);
	updateHeight(t);
	root=t;
}

(3)插入
往一颗AVL树中插入一个结点时,一定会有结点的平衡因子发生变化(变为2或者-2),这样以改结点为根结点的子树就会失衡,需要进行调整。只有从根结点到该插入结点的路径上的结点才可能出现平衡因子变化,可以证明:只要把最靠近插入结点的失衡结点调整正常,路径上的所有结点都会平衡。
假定最靠近插入结点的失衡结点为A,它的平衡因子是2或-2,以A为根结点的子树有以下几种情况:
1.LL型
A的左孩子的平衡因子为1时为LL型
在这里插入图片描述
调整过程:将C为根结点的子树看成是一个结点,再以A为根结点右旋就可以平衡。
在这里插入图片描述
2.LR型
A的左孩子的平衡因子为-1时为LR型
在这里插入图片描述
调整过程:先以C为根结点左旋将情况转化为LL型,再以A为根结点右旋。
在这里插入图片描述
3.与上面两种对称的还有RR型(结点A的右孩子的平衡因子为-1)和RL型(结点A的右孩子的平衡因子为1),结点A平衡因子为-2,调整情况与上述两种情况也是对应的。

树型条件调整方法
LLBF(root)=2,BF(root->lchild)=1将root右旋
LRBF(root)=2,BF(root->lchild)=-1将root->lchild左旋,再将root右旋
RRBF(root)=-2,BF(root->lchild)=-1将root左旋
RLBF(root)=-2,BF(root->lchild)=1将root->rchild右旋,再将root左旋

插入操作代码:

void insert(node* &root,int data){
	if(root==NULL){
		root=newNode(data);
		return;
	}
	if(data<root->data){
		insert(root->lchild,data);
		updateHeight(root);
		if(getBalancedFactor(root)==2){
			if(getBalancedFactor(root->lchild)==1)
				R(root);
			else if(getBalancedFactor(root->lchild)==-1){
				L(root->lchild);
				R(root);
			}
		}
	}
	else{
		insert(root->rchild,data);
		updateHeight(root);
		if(getBalancedFactor(root)==-2){
			if(getBalancedFactor(root->rchild)==-1)
				L(root);
			else if(getBanlancedFactor(root->rchild)==1){
				R(root->rchild);
				L(root);
			}
		}
	}
}

(4)AVL树的创建

node *Create(int data[],int n){
	node *root=NULL;
	for(int i=0;i<n;i++){
		insert(root,data[i]);
	}	
	return root;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值