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;
}
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;
}
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 = 0;            //新创的节点是个空树,高度为0
	}
	else if (key < root->key)        
	{
		root->left = insert(key, root->left);    //递归向左插入
		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);
		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;
}

猜你喜欢

转载自blog.csdn.net/slience_646898/article/details/81210258