1、搜索二叉树可能会出现一边树很长另一边树很短的极端情况,这样的话二叉树就会退化,这时我们就引出了AVL树这样的改良版。AVL树会控制两端树的高度差的绝对值小于1。(一般为右数高度减左树高度)

2、AVL树会通过平衡因子来控制,因为是右-左,所以插入左边平衡因子--,右边则++

3、基本结构:

AVL树_搜索二叉树

其中_parent是用来找上一节点进行链接

控制AVL的行为:

AVL树_头结点_02

其中除了插入函数其余函数与搜索二叉树相似。

4、插入函数:

bool Insert(const pair<K, V>& kv)
{
//若头结点为空则直接加
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}

	Node* parent = nullptr;
	Node* cur = _root;
	//kv.first相当于BST中的k
  //比较找插入的位置
	while (cur)
	{
		if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			return false;
		}
	}
//找到插入的父节点
	cur = new Node(kv);
	if (parent->_kv.first < kv.first)
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
  //插入链接
	cur->_parent = parent;

	// 更新平衡因子
	while (parent)
	{
  //左--,右++
		if (cur == parent->_left)
			parent->_bf--;
		else
			parent->_bf++;
//根据parent的平衡因子来判断是否向上更新
//为0结束
		if (parent->_bf == 0)
		{
			break;
		}
    //为1/-1
		else if (parent->_bf == 1 || parent->_bf == -1)
		{
			// 继续往上更新
			cur = parent;
			parent = parent->_parent;
		}
    //为2/-2,违背规则旋转处理
		else if (parent->_bf == 2 || parent->_bf == -2)
		{
			// 不平衡了,旋转处理
			if (parent->_bf == 2 && cur->_bf == 1)
			{
      //左单旋
				RotateL(parent);
			}
			else if (parent->_bf == -2 && cur->_bf == -1)
			{
      //右单旋
				RotateR(parent);
			}
			else if (parent->_bf == 2 && cur->_bf == -1)
			{
      //先右后左
				RotateRL(parent);
			}
			else
			{
      //先左后右
				RotateLR(parent);
			}

			break;
		}
		//若出错则报错
		else
		{
			assert(false);
		}
	}

	return true;
}

左单旋:

AVL树_头结点_03

这里子树的高度为h,h分为0和>=1

h==1:

AVL树_搜索二叉树_04

h>=1

AVL树_父节点_05

转完后,改变parent节点,若subRL为空则不链接parent,不为空则链接

还有parent的parent为空则:

AVL树_头结点_06

若不为空,parent在其父节点的左则向左链接,右同理:

AVL树_头结点_07

更新平衡因子:

AVL树_头结点_08

右单旋:

AVL树_搜索二叉树_09

与左单旋相似:

AVL树_搜索二叉树_10

AVL树_搜索二叉树_11

平衡因子的更新:

AVL树_搜索二叉树_12

AVL树_头结点_13