C++ AVL树

AVL树

  • 底层结构
  • AVL树(高度平衡搜索二叉树)
      • AVL树的插入
      • 四种旋转
        • 右单旋
        • 左单旋
        • 右左双旋
        • 左右双旋
    • AVL实现代码
    • AVL的性能

底层结构

map/set/multimap/multiset等这些容器其底层都是按照二叉搜索树来实现的但是二叉搜索树有其自身的缺陷,eg:往树中插入的元素有序或接近有序,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map,set等关联式容器的底层结构是对二叉树进行了平衡处理,即采用平衡树来来实现。

AVL树(高度平衡搜索二叉树)

二叉搜索树虽然可以缩短查找的效率,但如果数据有序或接近有序的二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下因此两位俄罗斯数学家发明了一种解决上述问题的方法:**当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),**即可降低树的高度,从而减少平均搜索长度。

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1
    每个结点增加平衡因子(不是必须的)
    如果一颗二叉搜索树是高度平衡的 ,它就是AVL树。如果它有N个结点,其高度保持在O(log2N),搜索时间复杂度O(log2N)

AVL树的插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可看成是二叉搜索树。
AVL的插入步骤:

  • 1、按照二叉搜索树的方式插入新节点
  • 2、调整平衡因子
一个结点的平衡因子是否更新取决于,它的左右子树的高度是否发生变化,插入一个结点,这个结点的祖先结点的平衡因子也可能需要更新!

新增节点的步骤:

1、新增结点在parent左边,parent->_bf–;
2、新增结点在parent右边,parent->_bf++;

  • 如果parent的平衡因子等于 1/-1,继续往上更新(说明parent所在的子树变了)
  • 如果parent的平衡因子等于0,停止更新(高度没变)
  • 如果parent的平衡因子等于2/-2,已经出现不平衡,需要旋转处理
    C++ AVL树_第1张图片

bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
		}
		//找到数据存储的位置,把数据插入
		Node* parent = _root, *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->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		//控制平衡
		//1、更新平衡因子
		//2、如果不平衡需要旋转
		while (parent != nullptr)//while(cur != _root)
		{
			if (parent->_left == cur)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}
			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				//parent所在的子树高度变了,会影响parant的parent,继续往上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//parent所在的子树已经不平衡,需要旋转处理
				if (parent->_bf == -2)
				{
					if (cur->_bf == -1)
					{
						//左高右低-》右单旋
						RotateR(parent);
					}
					else// cur->_buf == 1
					{
						//左右双旋
						RotateLR(parent);
					}
				}
				else//parent->_bf == 2
				{
					if (cur->_bf == 1)
					{
						//左单旋
						RotateL(parent);

					}
					else//cur->_bf == -1
					{
						//右左双旋
						RotateRL();
					}
				}
				break;
			}
			else
			{
				//说明在插入结点之前,树已经平衡或出错
				assert(false);
			}
		}
		return true;
	}

四种旋转

C++ AVL树_第2张图片

右单旋

新结点插入较高左子数的左侧—右单旋
C++ AVL树_第3张图片
C++ AVL树_第4张图片

void RotateR(Node* parent)
	{
		Node* subl = parent->_left;
		Node* sublr = subl->_right;
		parent->_left = sublr;
		if (sublr)
		{
			sublr->_parent = parent;
		}
		
		subl->_right = parent;
		Node* parentparent = parent->_parent;
		parent->_parent = subl;
		if (parent == _root)
		{
			//是一个独立的树
			_root = subl;
			_root->_parent = nullptr;
		}
		else
		{
			//只是子树,parent还有parent
			if (parentparent->_left == parent)
			{
				parentparent->_left = subl;
			}
			else
			{
				parentparent->_right = subl;
			}
			subl->_parent = parentparent;
		}
		subl->_bf = parent->_bf = 0;
	}

左单旋

新结点插入较高右子树的右侧–左单旋
C++ AVL树_第5张图片

void RotateL(Node* parent)
	{
		Node* subr = parent->_right;
		Node* subrl = subr->_left;

		parent->_right = subrl;
		if (subrl)
		{
			subrl->_parent = parent;
		}
		Node* parentparent = parent->_parent;
		subr->_left = parent;
		parent->_parent = subr;

		if (parent == _root)
		{
			//是独立的树
			_root = subr;
			_root->_parent = nullptr;
		}
		else
		{
			//是子树
			if (parentparent->_left == parent)
				parentparent->_left = subr;

			else
				parentparent->_right = subr;

			subr->_parent = parentparent;

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

右左双旋

新结点插入较高右子树的左侧–先右单旋再左单旋
C++ AVL树_第6张图片

void RotateRL(Node* parent)
	{
		Node* subr = parent->_right;
		Node* subrl = subr->_left;
		int bf = subrl->_bf;//提前保存平衡因子
		RotateR(parent->_right);
		RotateL(parent);
		if (bf == 1)
		{
			//是在c插入
			subr->_bf = 0;
			parent->_bf = -1;
			subrl->_bf = 0;
		}
		else if (bf == -1)
		{
			//在b插入
			parent->_bf = 0;
			subr->_bf = 1;
			subrl->_bf = 0;
		}
		else if (bf == 0)
		{
			//本身是新增结点
			parent->_bf = 0;
			subr->_bf = 0;
			subrl->_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);
		if (bf == -1)
		{
			//在b插入新结点
			subl->_bf = 0;
			parent->_bf = 1;
			sublr->_bf = 0;
		}
		else if (bf == 1)
		{
			//在c插入新结点
			subl->_bf = -1;
			parent->_bf = 0;
			sublr->_bf = 0;
		}
		else if (bf == 0)
		{
			//本身新增结点
			subl->_bf = 0;
			parent->_bf = 0;
			sublr->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

C++ AVL树_第7张图片

AVL实现代码

#pragma once
#include 
#include 
using namespace std;
template<class K,class V>
class AVLTreeNode
{
public:
	AVLTreeNode<K,V>* _left;
	AVLTreeNode<K,V>* _right;
	AVLTreeNode<K,V>* _parent;

	int _bf;//平衡因子
	//右子树 - 左子树
	pair<K,V> _kv;

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


template <class K,class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	AVLTree()
		:_root(nullptr)
	{}
	void Destory(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}
	~AVLTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}
	V& operator[](const K& key)
	{
		pair<Node*, bool> ret = Insert(make_pair(key, v()));
		return ret.first->_kv.second;
	}
	pair<Node*,bool> Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return make_pair(_root, true);
		}
		//找到数据存储的位置,把数据插入
		Node* parent = _root, *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 make_pair(cur,true);
			}
		}
		cur = new Node(kv);
		Node* newnode = cur;
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		//控制平衡
		//1、更新平衡因子
		//2、如果不平衡需要旋转
		while (parent != nullptr)//while(cur != _root)
		{
			if (parent->_left == cur)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}
			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				//parent所在的子树高度变了,会影响parant的parent,继续往上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//parent所在的子树已经不平衡,需要旋转处理
				if (parent->_bf == -2)
				{
					if (cur->_bf == -1)
					{
						//左高右低-》右单旋
						RotateR(parent);
					}
					else// cur->_buf == 1
					{
						//左右双旋
						RotateLR(parent);
					}
				}
				else//parent->_bf == 2
				{
					if (cur->_bf == 1)
					{
						//左单旋
						RotateL(parent);

					}
					else//cur->_bf == -1
					{
						//右左双旋
						RotateRL(parent);
					}
				}
				break;
			}
			else
			{
				//说明在插入结点之前,树已经平衡或出错
				assert(false);
			}
			
		}
		return make_pair(newnode,true);
	}	
	void RotateR(Node* parent)
	{
		Node* subl = parent->_left;
		Node* sublr = subl->_right;
		parent->_left = sublr;
		if (sublr)
		{
			sublr->_parent = parent;
		}
		
		subl->_right = parent;
		Node* parentparent = parent->_parent;
		parent->_parent = subl;
		if (parent == _root)
		{
			//是一个独立的树
			_root = subl;
			_root->_parent = nullptr;
		}
		else
		{
			//只是子树,parent还有parent
			if (parentparent->_left == parent)
			{
				parentparent->_left = subl;
			}
			else
			{
				parentparent->_right = subl;
			}
			subl->_parent = parentparent;
		}
		subl->_bf = parent->_bf = 0;
	}
	void RotateL(Node* parent)
	{
		Node* subr = parent->_right;
		Node* subrl = subr->_left;

		parent->_right = subrl;
		if (subrl)
		{
			subrl->_parent = parent;
		}
		Node* parentparent = parent->_parent;
		subr->_left = parent;
		parent->_parent = subr;

		if (parent == _root)
		{
			//是独立的树
			_root = subr;
			_root->_parent = nullptr;
		}
		else
		{
			//是子树
			if (parentparent->_left == parent)
				parentparent->_left = subr;

			else
				parentparent->_right = subr;

			subr->_parent = parentparent;

		}
		parent->_bf = subr->_bf = 0;
	}
	void RotateRL(Node* parent)
	{
		Node* subr = parent->_right;
		Node* subrl = subr->_left;
		int bf = subrl->_bf;//提前保存平衡因子
		RotateR(parent->_right);
		RotateL(parent);
		if (bf == 1)
		{
			//是在c插入
			subr->_bf = 0;
			parent->_bf = -1;
			subrl->_bf = 0;
		}
		else if (bf == -1)
		{
			//在b插入
			parent->_bf = 0;
			subr->_bf = 1;
			subrl->_bf = 0;
		}
		else if (bf == 0)
		{
			//本身是新增结点
			parent->_bf = 0;
			subr->_bf = 0;
			subrl->_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);
		if (bf == -1)
		{
			//在b插入新结点
			subl->_bf = 0;
			parent->_bf = 1;
			sublr->_bf = 0;
		}
		else if (bf == 1)
		{
			//在c插入新结点
			subl->_bf = -1;
			parent->_bf = 0;
			sublr->_bf = 0;
		}
		else if (bf == 0)
		{
			//本身新增结点
			subl->_bf = 0;
			parent->_bf = 0;
			sublr->_bf = 0;
		}
		else
		{
			assert(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;
	}
	bool Erase(const K& key)
	{
		//先找到删除值所在的结点
		//2、按搜索树规则分类删除,a、左为空 b、右为空 c、左右都不为空
		//3、更新平衡因子,如果不平衡-》旋转
		//与插入相反
		//删除在parent左:parent->_bf++
		//删除在parent右:parent->_bf--
		//  a、更新后parent->_bf == 0说明原来是 1/-1,把高的那边删除了,高度变,继续更新
		//  b、更新后parent->_bf == 1 || parent->_bf == -1 说明原来是0,高度不变,停止更新
		//  c、更新后parent->_bf == 2 || parent->_bf == -2 不平衡,旋转
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_kv.first << " : " << root->_kv.second << endl;
		_InOrder(root->_right);
	}
	void InOrder()
	{
		_InOrder(_root);

	}
	int _Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftheight = _Height(root->_left);
		int rightheight = _Height(root->_right);
		return rightheight > leftheight ? rightheight + 1 : leftheight + 1;
	}
	bool _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);
	}
	bool IsAVLTreeTrue()
	{
		return _Isbalance(_root);
	}
private:
	Node* _root;

};

AVL的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即log2(N)
但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:
插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

你可能感兴趣的:(C++,数据结构,c++,数据结构,AVL)