AVL树的实现

概念

1.为了解决二叉搜索树有序插入,会退化成链表,导致效率低下。

AVL树的左右子树高度差不超过1,所以AVL树的查找效率为logn。

2.在左子树高度增加,平衡因子减一,在右子树高度增加,平衡因子加一。

节点的定义

template<class key, class value>
	struct TreeNode
	{
		typedef TreeNode Node;
		TreeNode< key, value>* left;
		TreeNode< key, value>* right;
		TreeNode< key, value>* _parent;
		std::pair <key, value> data;
		int bf;//平衡因子
		TreeNode(const std::pair<key, value>& kv = kv())
			:left(nullptr)
			, right(nullptr)
			, _parent(nullptr)
			, data(kv)
			, bf(0)
		{}
	};

插入

这种情况是最简单的情况,只需找到插入位置即可,

当插入节点小于当前节点,那么去左子树找插入位置。

插入节点大于当前节点,那么去右子树寻找插入位置。

当前节点为空时,就是插入位置。

调平衡因子

1.插入之后树高度不变

这种情况插入只会影响父亲,不会影响祖先。

所以只需要修改父亲的平衡因子。

2.插入之后,高度增加

这种情况,树的高度增加,会影响整棵树的平衡因子,需要一直向上调整,直到当前节点为根节点。

旋转

在向上调节平衡因子的时候,发现|bf| > 1 ,进行旋转。

1.父亲和孩子在一条直线上

调节到黑色节点时bf == -2,进行右旋转,bf == 2 ,进行左旋转。

将橙色节点,连入黑色的左节点

黑色节点变为红色的右节点

红色在与黑色的父亲节点连接,没有父亲父亲节点变为nullptr

将黑色节点,和红色节点的平衡因子置为0。

2.父亲和孩子不在同一条直线上

如果只进行一次右旋还是会不平平衡。

调节到黑色节点时bf == -2,进行左右双旋转,bf == 2 ,进行右左双旋转。

先对红色节点进行一次左旋

在对黑色节点进行一次右旋

最后调平衡因子分三种情况

经过上图发现,橙色的左节点,变成了红色的右节点。

橙色的右节点,变成黑色的左节点。

1.当橙色的bf == -1

红 bf = 0

黑 bf = 1

橙 bf = 0

2.当橙色bf == 1

红 bf = -1

黑 bf = 0

橙 bf = 0

3.当橙色bf == 0 说明橙是新插入节点

红 bf = 0

黑 bf = 0

橙 bf = 0

完整代码

#pragma once
#include<iostream>
#include<assert.h>

namespace AVL
{
	template<class key, class value>
	struct TreeNode
	{
		typedef TreeNode Node;
		TreeNode< key, value>* left;
		TreeNode< key, value>* right;
		TreeNode< key, value>* _parent;
		std::pair <key, value> data;
		int bf;
		TreeNode(const std::pair<key, value>& kv = kv())
			:left(nullptr)
			, right(nullptr)
			, _parent(nullptr)
			, data(kv)
			, bf(0)
		{}
	};

	template<class key, class value>
	class AVLTree
	{
		typedef TreeNode<key, value> Node;
	public:


		bool insert(std::pair< key, value> p)
		{
			Node* cur = _root;
			if (cur == nullptr)
			{
				_root = new Node(p);
				return true;
			}
			Node* parent = nullptr;
			while (cur)
			{
				if (cur->data.first > p.first)
				{
					parent = cur;
					cur = cur->left;
				}
				else if (cur->data.first < p.first)
				{
					parent = cur;
					cur = cur->right;
				}
				else if (cur->data.first == p.first)
				{
					return false;
				}
			}
			//bf 左负 右正
			cur = new Node(p);
			if (p.first < parent->data.first)
			{
				parent->left = cur;
			}
			else
			{
				parent->right = cur;
			}
			cur->_parent = parent;
			//parent 的左右都不为空,只影响父亲
			//parent的左右有一个为空,影响祖先
			while (parent)
			{
				if (cur == parent->left)
				{
					parent->bf--;
				}
				else
				{
					parent->bf++;
				}

				if (parent->bf == 0)
				{
					break;
				}
				else if (parent->bf == -1 || parent->bf == 1)
				{
					cur = cur->_parent;
					parent = parent->_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))//右左双旋
					{
						RotateRL(parent);
					}
					else if ((parent->bf == -2 )&& (cur->bf == 1))//左右双旋
					{
						RotateLR(parent);
					}
				
					break;
				}
			}
			return true;
		}

		void inorder()
		{
			_inorder(_root);
		}

		void RotateL(Node* parent)
		{
			Node* subR = parent->right;
			Node* subRL = subR->left;
			Node* ppNode = parent->_parent;
			
			subR->left = parent;
			parent->_parent = subR;

			parent->right = subRL;
			if(subRL != nullptr)
			{
				subRL->_parent = parent;
			}

			if (parent == _root)
			{
				_root = subR;
				subR->_parent = nullptr;
			}
			else
			{
				if (parent == ppNode->left)
				{
					ppNode->left = subR;
				}
				else
				{
					ppNode->right = subR;
				}
				subR->_parent = ppNode;
			}
			subR->bf = 0;
			parent->bf = 0;
		}

		void RotateR(Node* parent)
		{
			Node* subL = parent->left;
			Node* subLR = subL->right;
			Node* ppNode = parent->_parent;
			
			subL->right = parent;
			parent->_parent = subL;
			
			parent->left = subLR;
			if(subLR != nullptr)
			{
				subLR->_parent = parent;
			}
			if (parent == _root)
			{
				_root = subL;
				subL->_parent = nullptr;
			}
			else
			{
				if (parent == ppNode->left)
				{
					ppNode->left = subL;
				}
				else
				{
					ppNode->right = subL;
				}
				subL->_parent = ppNode;
			}
			parent->bf = 0;
			subL->bf = 0;
		}

		void RotateRL(Node *parent)
		{
			Node* subR = parent->right;
			Node* subRL = subR->left;
			int bf = subRL->bf;
			RotateR(parent->right);
			RotateL(parent);
			subRL->bf = 0;
			//RL的右给R的左  左子树给P的右
			if (bf == 1)
			{
				subR->bf = 0;
				parent->bf = -1;
			}
			else if (bf == -1)
			{
				subR->bf = 1;
				parent->bf = 0;
			}
			else if(bf == 0)
			{
				subR->bf = 0;
				parent->bf = 0;
            }
			else
			{
				assert(false);
			}
		}

		void RotateLR(Node* parent)
		{
			Node* subL = parent->left;
			Node* subLR = subL->right;
			int bf = subLR->bf;
			
			RotateL(parent->left);
			RotateR(parent);
			subLR->bf = 0;
			if (bf == 1)
			{
				parent->bf = 0;
				subL->bf = -1;
			}
			else if (bf == -1)
			{
				parent->bf = 1;
				subL->bf = 0;
			}
			else if(bf == 0)
			{
				parent->bf = 0;
				subL->bf = 0;
			}
			else
			{
				assert(false);
			}
		}

	

		bool check()
		{
			int height = 0;
			return _check(_root,height);
		}


	private:

		Node* _root = nullptr;

		bool _check(Node* root,int &height)
		{
			if (root == nullptr)
			{
				height == 0;
				return true;
			}

			//检查左右子树高度差是否为1
			int leftheight = 0, rightheight = 0;
			if (!_check(root->left, leftheight) || ! _check(root->right, rightheight))
			{
				return false;
			}
			

			if (abs(rightheight - leftheight) >= 2)
			{
				std::cout << "高度错误" << std::endl;
				return false;
			}

			if (rightheight - leftheight != root->bf)
			{
				std::cout << "平衡因子错误" << std::endl;
				return false;
			}
			height = leftheight > rightheight ? leftheight+1 : rightheight+1;

			return true;
		}


		void _inorder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_inorder(root->left);
			 std::cout << "key:" << root->data.first << " " << "bf:" << root->bf << std::endl;
			 check();			
			 _inorder(root->right);
		}

	};

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值