数据结构:AVL树的旋转(平衡搜索二叉树)

1、AVL树简介

AVL树 是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树 。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。

  • 它的子树都是AVL树
  • 左右子树高度插(平衡因子)的绝对值不超过1

AVL树还是一个搜索二叉树,只不过因为普通的搜索二叉树有可能变成单只树,这样就使查找效率非常的低。我们就给普通的搜索二叉树增加了一个平衡因子来使AVL左右子树的高度差的绝对值不超过1

template<class K,class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;              
	pair<K, V> _kv;                          // 存储的键对
	int _bf;                                 // balance factor

	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv);
	bool IsBalance();
	void InOrder();
	void Height();

private:
	void RotateL(Node* parent);              //左旋转
	void RotateR(Node* parent);              //右旋转
	void RotateRL(Node* parent);             //右左旋转
	void RotateLR(Node* parent);             //左右旋转
	bool _IsBalance(Node* root);
	void _InOrder(Node* root);
	int _Height(Node* root);


	Node* _root = nullptr;
};

2、AVL树的插入

  • AVL树的插入前面和搜索二叉树的插入一模一样,只不过我们要注意平衡因子
  • 因为AVL树保持平衡是要平衡因子的绝对值不超过1,而插入会使平衡因子改变,所以我们也要要相应的旋转,使平衡因子的绝对值不超过一,我们又有几种情况
  1. 假如以pParent为根的子树不平衡,即pParent的平衡因子为2或者-2,分以下情况考虑

  2. parent的平衡因子为2,说明parent的右子树高,设parent的右子树的根为subR,当subR的平衡因子为1时,执行左单旋。当subR的平衡因子为-1时,执行右左双旋

  3. parent的平衡因子为-2,说明parent的左子树高,设parent的左子树的根为subL,当subL的平衡因子为-1是,执行右单旋。当subL的平衡因子为1时,执行左右双旋

  4. 旋转完成后,原parent为根的子树个高度降低,已经平衡,不需要再向上更新

    template<class K, class V>
    bool AVLTree<K, V>::Insert(const pair<K, V>& kv)
    {
    if (_root == nullptr)
    {
    _root = new Node(kv);
    return true;
    }

     Node* parent = nullptr;
     Node* cur = _root;
     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->_left = cur;
     }
     else
     {
     	parent->_right = cur;
     }
     cur->_parent = parent;
    
     // 更新平衡因子
     while (parent)
     {
     	if (cur == parent->_right)
     	{
     		parent->_bf++;
     	}
     	else
     	{
     		parent->_bf--;
     	}
    
     	if (parent->_bf == 1 || parent->_bf == -1)
     	{
     		// 继续更新
     		parent = parent->_parent;
     		cur = cur->_parent;
     	}
     	else if (parent->_bf == 0)
     	{
     		break;
     	}
     	else if (parent->_bf == 2 || parent->_bf == -2)
     	{
     		// 需要旋转处理 -- 1、让这颗子树平衡 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)
     		{
     			RotateLR(parent);
     		}
     		else if (parent->_bf == 2 && cur->_bf == -1)
     		{
     			RotateRL(parent);
     		}
     		else
     		{
     			assert(false);
     		}
    
     		break;
     	}
     	else
     	{
     		assert(false);
     	}
     }
    
     return true;
    

    }

2.1、左单旋

  1. subRL变成parent的右子树

  2. parent变成subR的左子树

  3. subR变成新根

  4. 更新平衡因子

    template<class K, class V>
    void AVLTree<K, V>::RotateL(Node* parent)
    {
    Node* subR = parent->_right;
    Node* subRL = subR->_left;

     parent->_right = subRL;
     subR->_left = parent;
    
     Node* parentParent = parent->_parent;
    
     parent->_parent = subR;
     if (subRL)
     	subRL->_parent = parent;
    
     if (_root == parent)
     {
     	_root = subR;
     	subR->_parent = nullptr;
     }
     else
     {
     	if (parentParent->_left == parent)
     	{
     		parentParent->_left = subR;
     	}
     	else
     	{
     		parentParent->_right = subR;
     	}
    
     	subR->_parent = parentParent;
     }
    
     parent->_bf = subR->_bf = 0;
    

    }

2.2、右单旋

60为parent,30为subL,b为subLR

  1. subLR变成parent的左子树

  2. parent变成subL的右子树

  3. subL变成新根

  4. 更新平衡因子

    template<class K, class V>
    void AVLTree<K, V>::RotateR(Node* parent)
    {
    Node* subL = parent->_left;
    Node* subLR = subL->_right;

     parent->_left = subLR;
     if (subLR)
     	subLR->_parent = parent;
    
     Node* parentParent = parent->_parent;
    
     subL->_right = parent;
     parent->_parent = subL;
    
     if (_root == parent)
     {
     	_root = subL;
     	subL->_parent = nullptr;
     }
     else
     {
     	if (parentParent->_left == parent)
     	{
     		parentParent->_left = subL;
     	}
     	else
     	{
     		parentParent->_right = subL;
     	}
    
     	subL->_parent = parentParent;
     }
    
     subL->_bf = parent->_bf = 0;
    

    }

2.3、左右双旋

先对30进行左单旋,先对90右单旋

template<class K, class V>
void AVLTree<K, V>::RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;

	RotateL(parent->_left);
	RotateR(parent);

	if (bf == 0)
	{
		parent->_bf = subL->_bf = subLR->_bf = 0;
	}
	else if (bf == -1)
	{
		parent->_bf = 1;
		subLR->_bf = 0;
		subL->_bf = 0;
	}
	else if (bf == 1)
	{
		parent->_bf = 0;
		subLR->_bf = 0;
		subL->_bf = -1;
	}
	else
	{
		assert(false);
	}
}

2.3、右左双旋

先对90进行右单旋,先对30左单旋

template<class K, class V>
void AVLTree<K, V>::RotateRL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int bf = subRL->_bf;

	RotateR(parent->_right);
	RotateL(parent);

	if (bf == 0)
	{
		// subRL自己就是新增
		parent->_bf = subR->_bf = subRL->_bf = 0;
	}
	else if (bf == -1)
	{
		// subRL的左子树新增
		parent->_bf = 0;
		subRL->_bf = 0;
		subR->_bf = 1;
	}
	else if (bf == 1)
	{
		// subRL的右子树新增
		parent->_bf = -1;
		subRL->_bf = 0;
		subR->_bf = 0;
	}
	else
	{
		assert(false);
	}
}

3、AVL树的性能

AVL树是带有平衡条件的二叉查找树,一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡 ,左右子树树高不超过1,和红黑树相比,它是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1)。不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时 的,由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况。

如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合

4、实现

#include<assert.h>

template<class K,class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;              
	pair<K, V> _kv;                          // 存储的键对
	int _bf;                                 // balance factor

	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv);
	bool IsBalance();
	void InOrder();
	void Height();

private:
	void RotateL(Node* parent);              //左旋转
	void RotateR(Node* parent);              //右旋转
	void RotateRL(Node* parent);             //右左旋转
	void RotateLR(Node* parent);             //左右旋转
	bool _IsBalance(Node* root);
	void _InOrder(Node* root);
	int _Height(Node* root);


	Node* _root = nullptr;
};

template<class K, class V>
bool AVLTree<K, V>::Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}

	Node* parent = nullptr;
	Node* cur = _root;
	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->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;

	// 更新平衡因子
	while (parent)
	{
		if (cur == parent->_right)
		{
			parent->_bf++;
		}
		else
		{
			parent->_bf--;
		}

		if (parent->_bf == 1 || parent->_bf == -1)
		{
			// 继续更新
			parent = parent->_parent;
			cur = cur->_parent;
		}
		else if (parent->_bf == 0)
		{
			break;
		}
		else if (parent->_bf == 2 || parent->_bf == -2)
		{
			// 需要旋转处理 -- 1、让这颗子树平衡 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)
			{
				RotateLR(parent);
			}
			else if (parent->_bf == 2 && cur->_bf == -1)
			{
				RotateRL(parent);
			}
			else
			{
				assert(false);
			}

			break;
		}
		else
		{
			assert(false);
		}
	}

	return true;
}

template<class K, class V>
void AVLTree<K, V>::RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

	parent->_right = subRL;
	subR->_left = parent;

	Node* parentParent = parent->_parent;

	parent->_parent = subR;
	if (subRL)
		subRL->_parent = parent;

	if (_root == parent)
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subR;
		}
		else
		{
			parentParent->_right = subR;
		}

		subR->_parent = parentParent;
	}

	parent->_bf = subR->_bf = 0;
}

template<class K, class V>
void AVLTree<K, V>::RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;

	parent->_left = subLR;
	if (subLR)
		subLR->_parent = parent;

	Node* parentParent = parent->_parent;

	subL->_right = parent;
	parent->_parent = subL;

	if (_root == parent)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subL;
		}
		else
		{
			parentParent->_right = subL;
		}

		subL->_parent = parentParent;
	}

	subL->_bf = parent->_bf = 0;
}

template<class K, class V>
void AVLTree<K, V>::RotateRL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int bf = subRL->_bf;

	RotateR(parent->_right);
	RotateL(parent);

	if (bf == 0)
	{
		// subRL自己就是新增
		parent->_bf = subR->_bf = subRL->_bf = 0;
	}
	else if (bf == -1)
	{
		// subRL的左子树新增
		parent->_bf = 0;
		subRL->_bf = 0;
		subR->_bf = 1;
	}
	else if (bf == 1)
	{
		// subRL的右子树新增
		parent->_bf = -1;
		subRL->_bf = 0;
		subR->_bf = 0;
	}
	else
	{
		assert(false);
	}
}

template<class K, class V>
void AVLTree<K, V>::RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;

	RotateL(parent->_left);
	RotateR(parent);

	if (bf == 0)
	{
		parent->_bf = subL->_bf = subLR->_bf = 0;
	}
	else if (bf == -1)
	{
		parent->_bf = 1;
		subLR->_bf = 0;
		subL->_bf = 0;
	}
	else if (bf == 1)
	{
		parent->_bf = 0;
		subLR->_bf = 0;
		subL->_bf = -1;
	}
	else
	{
		assert(false);
	}
}

template<class K, class V>
void AVLTree<K, V>::InOrder()
{
	_InOrder(_root);
	cout << endl;
}

template<class K, class V>
void AVLTree<K, V>::_InOrder(Node* root)
{
	if (root == nullptr)
		return;

	_InOrder(root->_left);
	cout << root->_kv.first << " ";
	_InOrder(root->_right);
}

template<class K, class V>
bool AVLTree<K, V>::IsBalance()
{
	return _IsBalance(_root);
}

template<class K, class V>
int AVLTree<K, V>::_Height(Node* root)
{
	if (root == nullptr)
		return 0;

	int leftHeight = _Height(root->_left);
	int rightHeight = _Height(root->_right);

	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

template<class K, class V>
void AVLTree<K, V>::Height()
{
	cout << _Height(_root) << endl;
}

template<class K, class V>
bool AVLTree<K,V>::_IsBalance(Node* root)
{
	if (root == nullptr)
		return true;

	int leftHeight = _Height(root->_left);
	int rightHeight = _Height(root->_right);
	if (rightHeight - leftHeight != root->_bf)
	{
		cout << root->_kv.first << "平衡因子异常" << endl;
		return false;
	}

	return abs(rightHeight - leftHeight) < 2
		&& _IsBalance(root->_left)
		&& _IsBalance(root->_right);
}
相关推荐
Amor风信子9 分钟前
华为OD机试真题---跳房子II
java·数据结构·算法
Ljubim.te1 小时前
软件设计师——数据结构
数据结构·笔记
_GR2 小时前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
无限大.2 小时前
c语言实例
c语言·数据结构·算法
@haihi3 小时前
冒泡排序,插入排序,快速排序,选择排序
数据结构·算法·排序算法
丢掉幻想准备斗争3 小时前
数据结构(栈和队列的实现)
数据结构
zengy54 小时前
Effective C++中文版学习记录(三)
数据结构·c++·学习·stl
&梧桐树夏7 小时前
【算法系列-链表】删除链表的倒数第N个结点
数据结构·算法·链表
QuantumStack7 小时前
【C++ 真题】B2037 奇偶数判断
数据结构·c++·算法
wclass-zhengge8 小时前
数据结构篇(绪论)
java·数据结构·算法