C++中的AVL树

AVL树概念

二叉搜索树遗留的问题:

  • 数据接近有序或接近有序,二叉搜索树就会退化成单支树,查找元素就相当于在顺序表中搜索元素效率低

解决方法:

  • 当向二叉搜索树中插入新结点的后,若能保证每个结点的左右子树高度差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索的长度,提高效率。

一颗具有以下性质的二叉搜索树或一颗AVL树:

  • 左右子树高度差(平衡因子)的绝对值不超过1(-1/0/1)。
  • 它的左右子树分别都为AVL树。
    在这里插入图片描述

AVL树节点的定义

template<class T>
struct AVLNode{

	AVLNode(const T& data=T()) :
 	       _pLeft(nullptr),
       	   _pRight(nullptr),
       	   _pParent(nullptr),
       	   _data(data),
       	   _bf(0){}	
       	   
	AVLNode<T>* _pLeft;  //左孩子
	AVLNode<T>* _pRight; //右孩子
	AVLNode<T>* _pParent;//双亲结点

	T _data;
	int _bf;//平衡因子
};

AVL树的插入

bool Insert(const T& data){
		if (_pRoot == nullptr){
			_pRoot = new Node(data);
			return true;
		}
		//找到待插入节点的位置
		Node* pCur = _pRoot;
		Node* pParent = nullptr;
		while (pCur){
			pParent = pCur;
			if (data > pCur->_data){
				pCur = pCur->_pRight;
			} 
			else if (data < pCur->_data){
				pCur = pCur->_pLeft;
			}
			else{
				return false;
			}
		}

		//插入新节点
		pCur = new Node(data);
		if (data < pParent->_data){
			pParent->_pLeft = pCur;
		}
		else{
			pParent->_pRight = pCur;
		}
		pCur->_pParent = pParent;

		//更新平衡因子
		while (pParent){
		//如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可
			if (pCur == pParent->_pLeft)
				pParent->_bf--;
			else
			//如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可
				pParent->_bf++;
		
			if (pParent->_bf == 0)
				break;
           // 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1, 此时以pParent为根的树的高度增加,需要继续向上更新
			else if (pParent->_bf == 1 || pParent->_bf == -1){
				pCur = pParent;
				pParent = pCur->_pParent;
			}
			//如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进行旋转处理
			else{
		        //pParent->_bf=2||-2 节点失去平衡
				if (pParent->_bf == 2){
					if (pCur->_bf == 1)
						RotateL(pParent);
					else
						RotateRL(pParent);
				}
				else{
					if (pCur->_bf == -1)
						RotateR(pParent);

					else
						RotateLR(pParent);
				}
				break;
			}
		}
		return true;
	}

AVL树的旋转

右单旋
  • 新节点插入较高左子树的左侧—左左:右单旋
    在这里插入图片描述
void RotateR(Node* pParent){
		Node* pSubL = pParent->_pLeft;
		Node* pSubLR = pSubL->_pRight;

		//改变pParent和pSubL孩子的指向
		pParent->_pLeft = pSubLR;
		if (pSubLR)
     		pSubLR->_pParent = pParent;

		pSubL->_pRight = pParent;

		//改变pParent和pSubL的双亲
		Node* pPParent = pParent->_pParent;
		pParent->_pParent = pSubL;
		pSubL->_pParent = pPParent;
        
		if (pPParent == nullptr){
			_pRoot = pSubL;
		}
		else{
			if (pParent == pPParent->_pLeft)
				pPParent->_pLeft = pSubL;
			else
				pPParent->_pRight = pSubL;
		}
		//更新平衡因子
		pParent->_bf = pSubL->_bf = 0;
	}
左单旋
  • 新节点插入较高右子树的右侧—右右:左单旋

在这里插入图片描述

void RotateL(Node* pParent){
		Node* pSubR = pParent->_pRight;
		Node* pSubRL = pSubR->_pLeft;

		pParent->_pRight = pSubRL;
		if (pSubRL)
			pSubRL->_pParent = pParent;

		pSubR->_pLeft = pParent;
		Node* pPParent = pParent->_pParent;
		pParent->_pParent = pSubR;
		pSubR->_pParent = pPParent;
		
		if (pPParent == nullptr){
			_pRoot = pSubR;
		}
		else{
			if (pParent == pPParent->_pLeft)
				pPParent->_pLeft = pSubR;
			else
				pPParent->_pRight = pSubR;
		}

		pParent->_bf = pSubR->_bf = 0;
	}
左右双旋
  • 新节点插入较高左子树的右侧—左右:先左单旋再右单旋
    在这里插入图片描述
void RotateLR(Node* pParent){
		Node* pSubL = pParent->_pLeft;
		Node* pSubLR = pSubL->_pRight;
		int bf = pSubLR->_bf;
		RotateL(pParent->_pLeft);
		RotateR(pParent);
	
		if (bf == -1){
			pParent->_bf = 1;
		}
		else if (bf == 1){
			pSubL->_bf = -1;
		}
	}

右左双旋
  • 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

在这里插入图片描述

void RotateRL(Node* pParent){
		Node* pSubR = pParent->_pRight;
		Node* pSubRL = pSubR->_pLeft;
		int bf = pSubRL->_bf;

		RotateR(pParent->_pRight);
		RotateL(pParent);
		if (bf == -1){
			pSubR->_bf = 1;
		}
		else if (bf == 1){
			pParent->_bf = -1;
		}
	}

AVL树的验证

size_t _Height(Node* pRoot){
		if (pRoot==nullptr){
			return 0;
		}
		size_t leftHeight = _Height(pRoot->_pLeft);
		size_t rightHeight = _Height(pRoot->_pRight);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

	bool _IsAVLTree(Node* pRoot){
	    //空树也是AVL树
		if (pRoot == nullptr){
			return true;
		}
		计算左右节点的平衡因子
		size_t leftHeight = _Height(pRoot->_pLeft);
		size_t rightHeight = _Height(pRoot->_pRight);

		int bf = rightHeight - leftHeight;
		if (abs(bf) > 1 || bf != pRoot->_bf){
			return false;
		}
		//左右子树如果都是AVL树,则该树一定是AVL树
		return _IsAVLTree(pRoot->_pLeft) && _IsAVLTree(pRoot->_pRight);
	}

AVL树的性能

  • AVL树是一棵绝对平衡的二叉搜索树,保证了搜索的时间复杂度为
    在这里插入图片描述
  • 如果要对AVL树进行一些结构修改,效率就会很低
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值