【C++】AVL树的插入与删除

系列文章目录

第二篇 数据结构学习之AVL树的插入与删除



前言

AVL 树是一种高度平衡的二叉搜索树,以发明者 Adelson-Velsky 和 Landis 的名字命名。它通过在插入和删除操作后调整树的平衡,确保任意节点的左右子树高度差不超过 1。与红黑树类似,AVL 树的查找、插入和删除的时间复杂度为O(logn),但 AVL 树更加严格地平衡,因此通常在查找操作上表现更好。本文将介绍 AVL 树的特点,并通过 C++ 代码实现插入、删除、平衡和旋转操作。


一、AVL 树的基本概念

AVL 树是一种自平衡的二叉搜索树,每个节点的左右子树的高度差(即平衡因子)不超过 1。AVL 树的插入和删除操作会自动调整树的平衡性,确保查找操作的时间复杂度始终为 O(logn)。

AVL 树的主要特点:
1,每个节点的左右子树的高度差不超过 1。
2,每次插入或删除节点后,如果树不平衡,则通过旋转操作进行调整,恢复平衡。
3,AVL 树中的平衡因子定义为:
平衡因子 = 左子树高度 - 右子树高度

  • 平衡因子为 1、0 或 -1 的节点被认为是平衡的。
  • 平衡因子超过 1 或 -1 的节点需要进行旋转调整。

二、参考视频链接

AVL树

三、代码实现

1. 定义节点类

在 C++ 中,我们首先定义一个节点类,包括颜色、值、左孩子、右孩子和父节点指针。

template<class K,class V>
struct AVLTreeNode
{
	typedef AVLTreeNode<K, V> Node;
	Node* _left;
	Node* _right;
	Node* _parent;
	pair<K, V> _kv;
	int _bf;//平衡因子,右树高度-左树高度

	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;
	Node* _root = nullptr;
};

2.旋转方法

包括左旋,右旋,左右双旋,右左双旋

//左旋
Node* RotateL(Node* parent)
{
	Node* Rnode = parent->_right;
	Node* RLnode = Rnode->_left;

	parent->_right = RLnode;
	//RLnode可能为空
	if (RLnode) RLnode->_parent = parent;
	Rnode->_left = parent;
	Node* ppnode = parent->_parent;
	parent->_parent = Rnode;

	if (parent == _root)
	{
		_root = Rnode;
	}
	else if (parent == ppnode->_left)
	{
		ppnode->_left = Rnode;
	}
	else
	{
		ppnode->_right = Rnode;
	}
	Rnode->_parent = ppnode;
	Rnode->_bf = 0;
	parent->_bf = 0;
	return Rnode;
}

//右旋
Node* RotateR(Node* parent)
{
	Node* Lnode = parent->_left;
	Node* LRnode = Lnode->_right;

	parent->_left = LRnode;
	//LRnode可能为空
	if (LRnode) LRnode->_parent = parent;
	Lnode->_right = parent;
	Node* ppnode = parent->_parent;
	parent->_parent = Lnode;

	if (parent == _root)
	{
		_root = Lnode;
	}
	else if (parent == ppnode->_left)
	{
		ppnode->_left = Lnode;
	}
	else
	{
		ppnode->_right = Lnode;
	}
	Lnode->_parent = ppnode;
	parent->_bf = 0;
	Lnode->_bf = 0;
	return Lnode;
}

//左右双旋
Node* RotateLR(Node* parent)
{
	Node* Lnode = parent->_left;
	Node* LRnode = Lnode->_right;
	int bf = LRnode->_bf;
	RotateL(Lnode);
	RotateR(parent); 

	LRnode->_bf = 0;
	if (bf == 1)
	{
		parent->_bf = 0;
		Lnode->_bf = -1;
	}
	else if (bf == -1)
	{
		parent->_bf = 1;
		Lnode->_bf = 0;
	}

	//该节点就是新增结点
	else if (bf == 0)
	{
		parent->_bf = 0;
		Lnode->_bf = 0;
	}
	else
	{
		//树出现问题
		assert(false);
	}
	return LRnode;
}

//右左双旋
Node* RotateRL(Node* parent)
{
	Node* Rnode = parent->_right;
	Node* RLnode = Rnode->_left;
	int bf = RLnode->_bf;
	RotateR(Rnode);
	RotateL(parent);
	RLnode->_bf = 0;
	if (bf == -1)
	{
		Rnode->_bf = 1;
		parent->_bf = 0;
	}
	else if (bf == 1)
	{
		Rnode->_bf = 0;
		parent->_bf = -1;
	}

	//该节点就是新增结点
	else if (bf == 0)
	{
		Rnode->_bf = 0;
		parent->_bf = 0;
	}
	else
	{
		//树出现问题
		assert(false);
	}
	return RLnode;
}

3.AVL树插入操作

在 AVL 树中插入节点后,需要检查是否打破了平衡。根据节点的平衡因子进行不同类型的旋转调整。

bool Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}
	Node* tmp = _root;
	Node* parent = nullptr;
	while (tmp)
	{
		if (tmp->_kv.first < kv.first)
		{
			parent = tmp;
			tmp = tmp->_right;
		}
		else if (tmp->_kv.first > kv.first)
		{
			parent = tmp;
			tmp = tmp->_left;
		}
		else
		{
			return false;
		}
	}
	tmp = new Node(kv);
	if (parent->_kv.first < kv.first)
	{
		parent->_right = tmp;
	}
	else
	{
		parent->_left = tmp;
	}
	tmp->_parent = parent;
	while (parent)
	{
		if (tmp == parent->_right)
		{
			parent->_bf++;
		}
		else
		{
			parent->_bf--;
		}
		if (parent->_bf == 0)
		{
			break;
		}
		else if (parent->_bf == 1 || parent->_bf == -1)
		{
			tmp = parent;
			parent = parent->_parent;
			
		}
		else if (parent->_bf == 2 || parent->_bf == -2)
		{
			//旋转调节
			if (parent->_bf == 2 && tmp->_bf == 1)
			{
				//左单旋
				RotateL(parent);
			}
			else if (parent->_bf == -2 && tmp->_bf == -1)
			{
				//右单旋
				RotateR(parent);
			}
			else if (parent->_bf == 2 && tmp->_bf == -1)
			{
				//右左双旋
				RotateRL(parent);
			}
			else if (parent->_bf == -2 && tmp->_bf == 1)
			{
				//左右双旋
				RotateLR(parent);
			}
			else
			{
				//树出现问题
				assert(false);
			}
			break;
		}
		else
		{
			//树已经是错误的
			assert(false);
			return false;
		}
	}
	return true;
}

4.AVL树删除操作

AVL 树的删除操作和插入类似,在删除节点后需要调整树的平衡,以确保 AVL 树的平衡性。

bool Erase(const K& key)
{
	Node* cur = _root;
	Node* parent = nullptr;
	while (cur)
	{
		if (cur->_kv.first < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			Node* del = cur;
			//找到了
			//左子树为空
			if (cur->_left == nullptr)
			{
				//根节点
				if (cur == _root)
				{
					_root = cur->_right;
				}
				else if (parent->_left == cur)
				{
					parent->_bf++;
					parent->_left = cur->_right;
				}
				else
				{
					parent->_bf--;
					parent->_right = cur->_right;
				}
				if (cur->_right) cur->_right->_parent = parent;
			}
			//右为空
			else if (cur->_right == nullptr)
			{
				if (cur == _root)
				{
					_root = cur->_left;
				}
				else if (parent->_left == cur)
				{
					parent->_bf++;
					parent->_left = cur->_left;
				}
				else
				{
					parent->_bf--;
					parent->_right = cur->_left;
				}
				if (cur->_left) cur->_left->_parent = parent;
			}
			//左右都不为空
			else
			{
				//替换法删除,替换右子树最左节点
				cur = cur->_right;
				parent = del;
				while (cur->_left)
				{
					parent = cur;
					cur = cur->_left;
				}
				del->_kv = cur->_kv;
				if (parent->_left == cur)
				{
					parent->_bf++;
					parent->_left = cur->_right;
				}
				else
				{
					parent->_bf--;
					parent->_right = cur->_right;
				}
				if (cur->_right) cur->_right->_parent = parent;
			}
			del = cur;
			//调节平衡因子
			while (parent)//最多更新到根
			{

				if (parent->_bf == 1 || parent->_bf == -1)
				{
					break;
				}

				else if (parent->_bf == 2 || parent->_bf == -2)
				{
					//右旋
					if (parent->_bf == -2 && parent->_left->_bf == -1)
					{
						parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

					}

					//左旋
					else if (parent->_bf == 2 && parent->_right->_bf == 1)
					{
						parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

					}

					//左右双旋
					else if (parent->_bf == -2 && parent->_left->_bf == 1)
					{
						parent = RotateLR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

					}

					//右左双旋
					else if (parent->_bf == 2 && parent->_right->_bf == -1)
					{
						parent = RotateRL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

					}

					//左旋
					else if (parent->_bf == 2 && parent->_right->_bf == 0)
					{

						Node* Tparent = parent;
						Node* Rnode = parent->_right;
						parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
						Tparent->_bf = 1;
						Rnode->_bf = -1;
						
					}
					//右旋
					else if (parent->_bf == -2 && parent->_left->_bf == 0)
					{
						Node* Tparent = parent;
						Node* Lnode = parent->_left;
						parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
						Tparent->_bf = -1;
						Lnode->_bf = 1;
						
					}
					else
					{
						assert(false);
					}
				}

				if (parent->_bf == 0)
				{
					cur = parent;
					parent = parent->_parent;
					if (parent && parent->_left == cur)
					{
						parent->_bf++;
					}
					else if (parent && parent->_right == cur)
					{
						parent->_bf--;
					}

				}


			}
			delete del;
			return true;
		}
		
		
	}
	return false;
}

四,总体代码

#pragma once
#include <assert.h>
#include <vector>
//旋转情况
//右树右边插入,parent的_bf为2,发生左单旋
//右树左边插入,parent的_bf为2,发生右左双旋
//左树左边插入,parent的_bf为2,发生右单旋
//左树右边插入,parent的_bf为2,发生左右双旋
//旋转后仍然是搜索树,从不平衡到平衡,高度减少

template<class K,class V>
struct AVLTreeNode
{
	typedef AVLTreeNode<K, V> Node;
	Node* _left;
	Node* _right;
	Node* _parent;
	pair<K, V> _kv;
	int _bf;//平衡因子,右树高度-左树高度

	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)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		Node* tmp = _root;
		Node* parent = nullptr;
		while (tmp)
		{
			if (tmp->_kv.first < kv.first)
			{
				parent = tmp;
				tmp = tmp->_right;
			}
			else if (tmp->_kv.first > kv.first)
			{
				parent = tmp;
				tmp = tmp->_left;
			}
			else
			{
				return false;
			}
		}
		tmp = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = tmp;
		}
		else
		{
			parent->_left = tmp;
		}
		tmp->_parent = parent;
		while (parent)
		{
			if (tmp == parent->_right)
			{
				parent->_bf++;
			}
			else
			{
				parent->_bf--;
			}
			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				tmp = parent;
				parent = parent->_parent;
				
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//旋转调节
				if (parent->_bf == 2 && tmp->_bf == 1)
				{
					//左单旋
					RotateL(parent);
				}
				else if (parent->_bf == -2 && tmp->_bf == -1)
				{
					//右单旋
					RotateR(parent);
				}
				else if (parent->_bf == 2 && tmp->_bf == -1)
				{
					//右左双旋
					RotateRL(parent);
				}
				else if (parent->_bf == -2 && tmp->_bf == 1)
				{
					//左右双旋
					RotateLR(parent);
				}
				else
				{
					//树出现问题
					assert(false);
				}
				break;
			}
			else
			{
				//树已经是错误的
				assert(false);
				return false;
			}
		}
		return true;
	}
	void InOrder()
	{
		_InOrder(_root);
	}

	int Height()
	{
		return _Height(_root);
	}

	bool IsBanlance()
	{
		int count = 0;
		return _IsBanlance(_root,count);
	}

	int size()
	{
		int num = 0;
		_size(_root,num);
		return num;
	}


	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				Node* del = cur;
				//找到了
				//左子树为空
				if (cur->_left == nullptr)
				{
					//根节点
					if (cur == _root)
					{
						_root = cur->_right;
					}
					else if (parent->_left == cur)
					{
						parent->_bf++;
						parent->_left = cur->_right;
					}
					else
					{
						parent->_bf--;
						parent->_right = cur->_right;
					}
					if (cur->_right) cur->_right->_parent = parent;
				}
				//右为空
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else if (parent->_left == cur)
					{
						parent->_bf++;
						parent->_left = cur->_left;
					}
					else
					{
						parent->_bf--;
						parent->_right = cur->_left;
					}
					if (cur->_left) cur->_left->_parent = parent;
				}
				//左右都不为空
				else
				{
					//替换法删除,替换右子树最左节点
					cur = cur->_right;
					parent = del;
					while (cur->_left)
					{
						parent = cur;
						cur = cur->_left;
					}
					del->_kv = cur->_kv;
					if (parent->_left == cur)
					{
						parent->_bf++;
						parent->_left = cur->_right;
					}
					else
					{
						parent->_bf--;
						parent->_right = cur->_right;
					}
					if (cur->_right) cur->_right->_parent = parent;
				}
				del = cur;
				//调节平衡因子
				while (parent)//最多更新到根
				{

					if (parent->_bf == 1 || parent->_bf == -1)
					{
						break;
					}

					else if (parent->_bf == 2 || parent->_bf == -2)
					{
						//右旋
						if (parent->_bf == -2 && parent->_left->_bf == -1)
						{
							parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

						}

						//左旋
						else if (parent->_bf == 2 && parent->_right->_bf == 1)
						{
							parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

						}

						//左右双旋
						else if (parent->_bf == -2 && parent->_left->_bf == 1)
						{
							parent = RotateLR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

						}

						//右左双旋
						else if (parent->_bf == 2 && parent->_right->_bf == -1)
						{
							parent = RotateRL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent

						}

						//左旋
						else if (parent->_bf == 2 && parent->_right->_bf == 0)
						{

							Node* Tparent = parent;
							Node* Rnode = parent->_right;
							parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
							Tparent->_bf = 1;
							Rnode->_bf = -1;
							
						}
						//右旋
						else if (parent->_bf == -2 && parent->_left->_bf == 0)
						{
							Node* Tparent = parent;
							Node* Lnode = parent->_left;
							parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
							Tparent->_bf = -1;
							Lnode->_bf = 1;
							
						}
						else
						{
							assert(false);
						}
					}

					if (parent->_bf == 0)
					{
						cur = parent;
						parent = parent->_parent;
						if (parent && parent->_left == cur)
						{
							parent->_bf++;
						}
						else if (parent && parent->_right == cur)
						{
							parent->_bf--;
						}

					}


				}
				delete del;
				return true;
			}
			
			
		}
		return false;
	}

	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				cur = cur->_right;
			}
			else if (cur->_kv.first > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

private:

	void _size(const Node* root, int& num)
	{
		if (root == nullptr)
		{
			return ;
		}
		_size(root->_left, num);
		++num;
		_size(root->_right, num);
	}

	bool _IsBanlance(Node* root,int& count)
	{
		if (root == nullptr)
		{
			count = 0;
			return true;
		}
		int left = 0, right = 0;
		if (!_IsBanlance(root->_left,left) || !_IsBanlance(root->_right,right))
		{
			return false;
		}
		if (abs(right - left) >= 2)
		{
			cout << "平衡因子绝对值>=2" << endl;
			return false;
		}
		else if (right - left != root->_bf)
		{
			cout << "平衡因子异常" << endl;
			return false;
		}
		count = left > right ? left + 1 : right + 1;
		return true;
		
	}

	int _Height(const Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}

		int left = _Height(root->_left);
		int right = _Height(root->_right);
		return left > right ? left + 1 : right + 1;
	}

	void _InOrder(const Node* node)
	{
		if (node == nullptr)
		{
			return;
		}
		_InOrder(node->_left);
		cout << node->_kv.first << ":" << node->_kv.second << endl;
		_InOrder(node->_right);
	}

	//左旋
	Node* RotateL(Node* parent)
	{
		Node* Rnode = parent->_right;
		Node* RLnode = Rnode->_left;

		parent->_right = RLnode;
		//RLnode可能为空
		if (RLnode) RLnode->_parent = parent;
		Rnode->_left = parent;
		Node* ppnode = parent->_parent;
		parent->_parent = Rnode;

		if (parent == _root)
		{
			_root = Rnode;
		}
		else if (parent == ppnode->_left)
		{
			ppnode->_left = Rnode;
		}
		else
		{
			ppnode->_right = Rnode;
		}
		Rnode->_parent = ppnode;
		Rnode->_bf = 0;
		parent->_bf = 0;
		return Rnode;
	}

	//右旋
	Node* RotateR(Node* parent)
	{
		Node* Lnode = parent->_left;
		Node* LRnode = Lnode->_right;

		parent->_left = LRnode;
		//LRnode可能为空
		if (LRnode) LRnode->_parent = parent;
		Lnode->_right = parent;
		Node* ppnode = parent->_parent;
		parent->_parent = Lnode;

		if (parent == _root)
		{
			_root = Lnode;
		}
		else if (parent == ppnode->_left)
		{
			ppnode->_left = Lnode;
		}
		else
		{
			ppnode->_right = Lnode;
		}
		Lnode->_parent = ppnode;
		parent->_bf = 0;
		Lnode->_bf = 0;
		return Lnode;
	}

	//左右双旋
	Node* RotateLR(Node* parent)
	{
		Node* Lnode = parent->_left;
		Node* LRnode = Lnode->_right;
		int bf = LRnode->_bf;
		RotateL(Lnode);
		RotateR(parent); 

		LRnode->_bf = 0;
		if (bf == 1)
		{
			parent->_bf = 0;
			Lnode->_bf = -1;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			Lnode->_bf = 0;
		}

		//该节点就是新增结点
		else if (bf == 0)
		{
			parent->_bf = 0;
			Lnode->_bf = 0;
		}
		else
		{
			//树出现问题
			assert(false);
		}
		return LRnode;
	}

	//右左双旋
	Node* RotateRL(Node* parent)
	{
		Node* Rnode = parent->_right;
		Node* RLnode = Rnode->_left;
		int bf = RLnode->_bf;
		RotateR(Rnode);
		RotateL(parent);
		RLnode->_bf = 0;
		if (bf == -1)
		{
			Rnode->_bf = 1;
			parent->_bf = 0;
		}
		else if (bf == 1)
		{
			Rnode->_bf = 0;
			parent->_bf = -1;
		}

		//该节点就是新增结点
		else if (bf == 0)
		{
			Rnode->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			//树出现问题
			assert(false);
		}
		return RLnode;
	}

private:
	Node* _root = nullptr;
};

总结

这里附带一下测试代码

void test_AVLTree1()
{
	//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };
	AVLTree<int, int> al;
	for (auto e : a)
	{
		al.Insert(make_pair(e, e));
		cout << e << "->" << al.IsBanlance() << endl;
	}
	al.InOrder();
	cout << al.IsBanlance() << endl;
}

void test_AVLTree2()
{
	const int N = 3500000;
	vector<int> v;
	v.reserve(N);
	srand(time(0));
	for (size_t i = 0; i < N; i++)
	{
		v.push_back((rand() + i));
	
	}
	//for (auto e : v)
	//{
	//	cout << e << "   " ;
	//}
	cout << endl;
	size_t begin2 = clock();
	AVLTree<int, int> t;
	for (auto e : v)
	{
		t.Insert(make_pair(e, e));
	}
	size_t end2 = clock();
	cout << t.IsBanlance() << endl;
	cout << "Insert:" << end2 - begin2 << endl;
	cout <<"Height:"<< t.Height() << endl;
	cout << "size:"<<t.size() << endl;
	size_t begin1 = clock();
	int flag = 0;
	for (auto e : v)
	{
		t.Find(e);
		t.Erase(e);
	/*	int i = t.IsBanlance();
		if (i == 0)
		{
			flag++;
		}*/
		
		
	}
	cout << "flag:" << flag << endl;
	for (size_t i = 0; i < N; i++)
	{
		t.Find((rand() + i));
		
	}
	size_t end1 = clock();
	cout << "Find:" << end1 - begin1 << endl;
}

AVL 树是理论上最早提出的自平衡二叉搜索树之一,以其严格的平衡性保障了快速的数据查找操作。在查找密集的应用中,AVL 树因其优越的平衡性被广泛采用。尽管插入和删除操作在 AVL 树中较为复杂,但它依然是一种有效的数据结构选择,特别适合那些更注重查找效率的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值