C++之AVL树的插入实现

该文章详细介绍了如何在C++中实现AVL树的插入功能,包括AVLTreeNode节点定义、AVLTree类结构、四种旋转操作(左单旋、右单旋、左右双旋、右左双旋)以及插入函数的具体实现。同时,文章还提供了测试AVLTree是否平衡的函数,确保插入后树的平衡性。

C++之AVL树的插入实现

在这里插入图片描述

1.引言

​ 众所周知,在我们使用普通的搜索二叉树的时候,难免会出现插入的数据总是过大或者过小,从而导致歪脖子树的情况出现,由此情况下AVL树便运营而生。AVLTree是一种在普通搜索二叉树上升级改造之后趋近于绝对平衡的结构,构建AVLTree的一种方法是引入平衡因子的方法,使得每一个左右子树的高度差的绝对值都不超过2,也就是只会有1,0,-1的这三种情况。

一般情况下,一棵AVLTree树应该具有:

1.它的左右子树都是AVL树

2.左右子树高度之差(平衡因子)绝对值不超过1

2.具体实现

整个过程我们会实现:

1.AVLTreeNode节点定义

2.AVLTree类定义

3.四种旋转的实现

4.AVLTree类中Insert()函数定义

5.测试AVLTree是否成功函数

2.1AVLTree节点定义

整个节点我们采用三叉链结构(左、右、父亲指针)和使用KV模型,并且最重要的是每个节点都会有一个bf平衡因子的整数衡量。

template<class K,class V>
	struct AVLTreeNode
	{
		AVLTreeNode<K, V>* _left;//左指针
		AVLTreeNode<K, V>* _right;//右指针
		AVLTreeNode<K, V>* _parent;//双亲指针
		pair<K, V> _kv;//存放数据的kv的pair对
		int _bf;//平衡因子

		AVLTreeNode(const pair<K,V>& kv) //构造函数
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_kv(kv)
			,_bf(0)
		{}

	};

2.1 AVLTree的类结构定义

整个类:

​ public:我们需要一个Insert()插入函数、走中序Inorder函数、判高度Height()函数和判断平衡Isbalance()函数

​ private:_root根节点与四种旋转函数

template<class K,class V>
	class AVLTree
	{
		typedef AVLTreeNode<K,V> Node;
	public:
		bool Insert(const pair<K, V>& kv) {}
		void Inorder() {}
		int _Height(){}
		bool Isbalance(){}
        
        private:
        bool _Isbalance(Node* root)
			{}

			int _Height(Node* root)
			{}

			void _Inorder(Node* root)
			{}

			void RotateL(Node* parent)
			{}
			void RotateR(Node* parent)
			{}

			void RotateLR(Node* parent)
			{}

			void RotateRL(Node* parent)
			{}

2.2四种旋转实现

​ 首先我们要知道我们为什么要旋转? 之前我们提到了,当平衡因子不超过2的时候,才能称之为AVLTree,不过在插入的过程中,总会有一次使得平衡因子绝对值等于2,那么这个时候我们就需要旋转来降低树的高度了。而旋转具体又能分为四种旋转:

1.左单旋 2.右单旋 3.左右双旋 4.右左双旋

2.2.1新节点插入较高右子树的右侧–左单旋

在这里插入图片描述

void RotateL(Node* parent)
			{
				Node* subR = parent->_right;
				Node* subRL = subR->_left;

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

				Node* pparent = parent->_parent;
				subR->_left = parent;
				parent->_parent = subR;

				//判断双亲的双亲节点pparent

				if (pparent == nullptr)
				{
					_root = subR;
					_root->_parent = nullptr;
				}

				else
				{
					if (pparent->_left == parent)
					{
						pparent->_left = subR;
					}
					else
					{
						pparent->_right = subR;
					}
					subR->_parent = pparent;

				}
				parent->_bf = subR->_bf = 0;
			}
2.2.2新节点插入较高左子树的右侧–右单旋

在这里插入图片描述

void RotateR(Node* parent)
			{
				Node* subL = parent->_left;
				Node* subLR = subL->_right;

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

				Node* pparent = parent->_parent;
				subL->_right = parent;
				parent->_parent = subL;

				if (pparent == nullptr)
				{
					_root = subLR;
					_root->_parent = nullptr;
				}
				else
				{
					if (pparent->_left == parent)
					{
						pparent->_left = subL;
					}
					else
					{
						pparent->_right = subL;
					}
					subL->_parent = pparent;
				}
				parent->_bf = subL->_bf = 0;
			}
2.2.3新节点插入较高左子树的右侧–左右双旋

在这里插入图片描述

void RotateLR(Node* parent)
			{
				Node* subL = parent->_left;
				Node* subLR = subL->_right;
				int bf = subLR->_bf;

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

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

			
			}
2.2.4新节点插入较高右子树的左侧–右左双旋

在这里插入图片描述

void RotateRL(Node* parent)
			{
				Node* subR = parent->_right;
				Node* subRL = parent->_left;
				int bf = subRL->_bf;

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

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


			}

2.3 Insert插入函数的具体实现

关键思路:在插入后当前最近插入节点的平衡因子为0时,不进行处理

​ 在插入后当前最近插入节点的平衡因子为1或者-1时,需要处理往上更新

​ 在插入后当前最近插入节点的平衡因子为2或者-2时,需要旋转处理

bool Insert(const pair<K, V>& kv)
		{
			if (_root == nullptr) //为空root即为新增节点
			{
				_root = new Node(kv);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;

			while (cur) //走到最下边
			{
				if (cur->_kv.first > kv.first)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (cur->_kv.first < kv.first)
				{
					parent = cur;
					cur = cur->_right;
				}
				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->_left)
				{
					parent->_bf--;
				}
					
				else
				{
					parent->_bf++;
				}

				//判断
				if (parent->_bf == 1 || parent->_bf == -1)
				{
					parent = parent->_parent;
					cur = cur->_parent;
				}

				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)
					{
						RotateLR(parent);//左右双旋
					}
					else if (parent->_bf == 2 && cur->_bf == -1)
					{
						RotateRL(parent);//右左双旋
					}
					else
					{
						assert("false");
					}

					break;
				}

				else if (parent->_bf == 0)//bf==0,不做处理
				{
					break;
				}
				else
				{
					assert("false");
				}
				

			}



			return true;
		}

2.4测试AVLTree是否成功

​ 测试的思路是先通过Height高度函数算出AVLTree的左右子树高度,随后递归检测左右子树的高度差,若有一个不满足即驳回。

		int _Height(Node* root) //高度函数
			{
				if (root == NULL)
					return 0;
				
				int leftH = _Height(root->_left);
				int rightH = _Height(root->_right);

				return leftH > rightH ? leftH + 1 : rightH + 1;

			}
			
		bool _Isbalance(Node* root)//判断平衡函数
			{
				if (root == NULL)
					return true;

				int leftH = _Height(root->_left);
				int rightH = _Height(root->_right);

				if (rightH - leftH != root->_bf)
				{
					cout << root->_kv.first << ":" << "平衡因子异常" << endl;
					return false;
				}

				return abs(leftH - rightH) < 2
					&& _Isbalance(root->_left)
					&& _Isbalance(root->_right);


			}

2.6 测试结果

测试代码

void testAVLTree()
	{
		AVLTree<int, int> lt;
		lt.Insert(make_pair(1,1));
		lt.Insert(make_pair(2,2));
		lt.Insert(make_pair(7,7));
		lt.Insert(make_pair(3,3));
		lt.Insert(make_pair(4,4));

		lt.Inorder();
		cout << endl;
		cout<<lt._Height();
		cout << endl;
		cout<<lt.Isbalance();
	}

在这里插入图片描述

2.7 全部代码

#pragma once
namespace Arthur
{
	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;

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

			while (cur)
			{
				if (cur->_kv.first > kv.first)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (cur->_kv.first < kv.first)
				{
					parent = cur;
					cur = cur->_right;
				}
				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->_left)
				{
					parent->_bf--;
				}
					
				else
				{
					parent->_bf++;
				}

				//判断
				if (parent->_bf == 1 || parent->_bf == -1)
				{
					parent = parent->_parent;
					cur = cur->_parent;
				}

				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)
					{
						RotateLR(parent);
					}
					else if (parent->_bf == 2 && cur->_bf == -1)
					{
						RotateRL(parent);
					}
					else
					{
						assert("false");
					}

					break;
				}

				else if (parent->_bf == 0)
				{
					break;
				}
				else
				{
					assert("false");
				}
				

			}



			return true;
		}

		void Inorder()
		{
			_Inorder(_root);
		}

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

		bool Isbalance()
		{
			return _Isbalance(_root);
		}

		
		private:

			bool _Isbalance(Node* root)
			{
				if (root == NULL)
					return true;

				int leftH = _Height(root->_left);
				int rightH = _Height(root->_right);

				if (rightH - leftH != root->_bf)
				{
					cout << root->_kv.first << ":" << "平衡因子异常" << endl;
					return false;
				}

				return abs(leftH - rightH) < 2
					&& _Isbalance(root->_left)
					&& _Isbalance(root->_right);


			}

			int _Height(Node* root)
			{
				if (root == NULL)
					return 0;
				
				int leftH = _Height(root->_left);
				int rightH = _Height(root->_right);

				return leftH > rightH ? leftH + 1 : rightH + 1;

			}

			void _Inorder(Node* root)
			{
				if (root == nullptr)
					return;

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

			void RotateL(Node* parent)
			{
				Node* subR = parent->_right;
				Node* subRL = subR->_left;

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

				Node* pparent = parent->_parent;
				subR->_left = parent;
				parent->_parent = subR;

				//判断双亲的双亲节点pparent

				if (pparent == nullptr)
				{
					_root = subR;
					_root->_parent = nullptr;
				}

				else
				{
					if (pparent->_left == parent)
					{
						pparent->_left = subR;
					}
					else
					{
						pparent->_right = subR;
					}
					subR->_parent = pparent;

				}
				parent->_bf = subR->_bf = 0;
			}
			void RotateR(Node* parent)
			{
				Node* subL = parent->_left;
				Node* subLR = subL->_right;

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

				Node* pparent = parent->_parent;
				subL->_right = parent;
				parent->_parent = subL;

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

			void RotateLR(Node* parent)
			{
				Node* subL = parent->_left;
				Node* subLR = subL->_right;
				int bf = subLR->_bf;

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

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

			
			}

			void RotateRL(Node* parent)
			{
				Node* subR = parent->_right;
				Node* subRL = parent->_left;
				int bf = subRL->_bf;

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

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


			}
	private:
		Node* _root = nullptr;
	};


	void testAVLTree()
	{
		AVLTree<int, int> lt;
		lt.Insert(make_pair(1,1));
		lt.Insert(make_pair(2,2));
		lt.Insert(make_pair(7,7));
		lt.Insert(make_pair(3,3));
		lt.Insert(make_pair(4,4));

		lt.Inorder();
		cout << endl;
		cout<<lt._Height();
		cout << endl;
		cout<<lt.Isbalance();
	}

}

RL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = parent->_left;
int bf = subRL->_bf;

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

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


		}
private:
	Node* _root = nullptr;
};


void testAVLTree()
{
	AVLTree<int, int> lt;
	lt.Insert(make_pair(1,1));
	lt.Insert(make_pair(2,2));
	lt.Insert(make_pair(7,7));
	lt.Insert(make_pair(3,3));
	lt.Insert(make_pair(4,4));

	lt.Inorder();
	cout << endl;
	cout<<lt._Height();
	cout << endl;
	cout<<lt.Isbalance();
}

}


评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arthur___Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值