AVL平衡二叉查找树

AVL树是带AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。

有平衡条件的二叉查找树,这个平衡条件要容易保持,保证树的深度是O(logN)。定义AVL树是每个节点左子树和右子数高度最多差1的平衡二叉树。AVL树是对BST树的一种优化,我们知道BST树插入的最坏情况是退化为线性数组,这样就大大降低了二分查找的效率,而AVL树在插入的时候会做旋转优化尽量让这个树左右平衡,从而提高了二分查找的效率。

和红黑树比较,它是严格的平衡二叉树,如果插入或删除后不满足平衡条件则会旋转调平衡,而旋转是耗费时间的,AVL树适用于插入删除比较少而查找多的情况。windows对进程地址空间的管理用到了AVL树。

核心:旋转

在每一次插入数值之后,树的平衡性都可能被破坏,这时可以通过一个简单的操作来矫正平衡——旋转。

旋转的目的就是减少高度,通过降低整棵树的高度来平衡。哪边的树高,就把那边的树向上旋转,通过旋转可以降低高度。

插入节点时分四种情况,四种情况对应的旋转方法是不同的:

例如对于被破坏平衡的节点 a 来说:

插入方式描述旋转方式
LL在a的左子树根节点的左子树上插入节点而破坏平衡右旋转
RR在a的右子树根节点的右子树上插入节点而破坏平衡左旋转
LR在a的左子树根节点的右子树上插入节点而破坏平衡先左旋后右旋
RL在a的右子树根节点的左子树上插入节点而破坏平衡先右旋后左旋

基本操作:

#include<iostream>
#include<algorithm>
using namespace std; 

typedef struct node             //avl树的声明
{
	int key;
	int height;
	struct node *left;
	struct node *right;
}node,*avl;


int get_height(avl root)       //获取avl树的高度,这里空树高度定义为0
{
	return  ((root == NULL) ? 0 : (root->height));
}


avl left_left(avl root)        //左左插入情况,需要右单旋
{
	avl k = root->left;
	root->left = k->right;
	k->right = root;
	root->height = max(get_height(root->left), get_height(root->right)) + 1; //更新旋转后节点的高度,每个节点的高度都是其左右子树最高高度加1
	k->height = max(get_height(k->left), get_height(k->right)) + 1;
    root=k;
    return root;
}
avl right_right(avl root)     //右右插入情况,需要左单旋,原理同上
{
	avl k = root->right;
	root->right = k->left;
	k->left = root;
	root->height = max(get_height(root->left), get_height(root->right)) + 1; 
	k->height = max(get_height(k->left), get_height(k->right)) + 1;
    root=k;
    return root;
}
avl left_right(avl root)     //左右插入情况,需要先左旋再右旋
{
	root->left = right_right(root->left);   //对root->left左旋化为左左插入情况,然后再右旋
	return left_left(root);
}
avl right_left(avl root)    //右左插入情况,需要先右旋再左旋
{
	root->right = left_left(root->right);  //对root->right右旋化为右右插入情况,然后再左旋
	return right_right(root);
}


avl insert(int key, avl root)       //对avl树的添加操作,传入添加的元素和根节点。插入函数有返回值就不需要解引用了
{
	if (root == NULL)                //创建新节点
	{
		root = new node;
		root->key = key;
		root->left = root->right = NULL;
		root->height = 1;            //新创的节点高度为1
	}
	else if (key < root->key)        
	{
		root->left = insert(key, root->left);    //递归向左插入
        updatahegiht(root);
		if (get_height(root->left) - get_height(root->right) == 2)  //如果插入引起失衡,需要旋转调整
		{
			if (key < root->left->key)       //左左插入情况
				root = left_left(root);
			else                             //否则就是左右插入情况
				root = left_right(root);
		}
	}
	else if (key > root->key)
	{
		root->right = insert(key, root->right);
        updatahegiht(root);
		if (get_height(root->right) - get_height(root->left) == 2)
		{
			if (key > root->right->key)
				root = right_right(root);
			else
				root = right_left(root);
		}
	}
	else
		cout << "不允许添加相同元素的值!" << endl;       //与bst一样,不允许重复插入相同元素
	return root;
}

PAT1066 Root of AVL Tree (25 分)

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

 

 

 

 

Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

 

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the root of the resulting AVL tree in one line.

Sample Input 1:

5
88 70 61 96 120

Sample Output 1:

70

Sample Input 2:

7
88 70 61 96 120 90 65

Sample Output 2:

88
#include<iostream>
#include<algorithm>
using namespace std;  

typedef struct node            
{
	int key;
	int height;
	struct node *left;
	struct node *right;
}node,*avl;

int get_height(avl root)      //获取树高,计算是否失衡,失衡则做出相应的旋转操作
{
	return  ((root == NULL) ? 0 : (root->height));
}
void updatahegiht(avl &root)  //更新树高
{
    root->height = max(get_height(root->left), get_height(root->right)) + 1;
}
avl left_left(avl root)        
{
	avl k = root->left;
	root->left = k->right;
	k->right = root;
	updatahegiht(root);
	updatahegiht(k);
	root=k;
	return root;
}
avl right_right(avl root)     
{
	avl k = root->right;
	root->right = k->left;
	k->left = root;
    updatahegiht(root);
	updatahegiht(k);
	root=k;
	return root;
}
avl left_right(avl root)     
{
	root->left = right_right(root->left);  
	return left_left(root);
}
avl right_left(avl root)    
{
	root->right = left_left(root->right);  
	return right_right(root);
} 
avl insert(int key, avl root)       
{
	if (root == NULL)              
	{
		root = new node;
		root->key = key;
		root->left = root->right = NULL;
		root->height = 1;           
	}
	else if (key < root->key)        
	{
		root->left = insert(key, root->left);   
		updatahegiht(root);
		if (get_height(root->left) - get_height(root->right) == 2)  
		{
			if (key < root->left->key)      
				root = left_left(root);
			else                            
				root = left_right(root);
		}
	}
	else if (key > root->key)
	{
		root->right = insert(key, root->right);
		updatahegiht(root);
		if (get_height(root->right) - get_height(root->left) == 2)
		{
			if (key > root->right->key)
				root = right_right(root);
			else
				root = right_left(root);
		}
	}
	return root;
}
int main(){
	int n;
	scanf("%d",&n);
	avl root=NULL;          //注意要赋初值!
	for(int i=0;i<n;i++){
		int tmp;
		scanf("%d",&tmp);
		root=insert(tmp,root);
	}
	printf("%d",root->key);
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值