C++ AVL树

Posted qnbk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 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,已经出现不平衡,需要旋转处理

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;
	

四种旋转

右单旋

新结点插入较高左子数的左侧—右单旋

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);
		
	

AVL实现代码

#pragma once
#include <iostream>
#include <assert.h>
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;
		NodeC++类实现AVL树

大话数据结构C语言57 平衡二叉树(AVL树)

C++从入门到入土第二十一篇:二叉搜索树之AVL树

C++从入门到入土第二十一篇:二叉搜索树之AVL树

C++从入门到入土第二十一篇:二叉搜索树之AVL树

平衡树AVL树