C++:AVL树

AVL tree 是一个“加上了额外平衡条件”的二叉搜索树,其平衡条件的建立是为了保证整棵树的深度为O(logN)。

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

  1. 它的左右子树都是AVL树
  2. 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

AVL树节点的定义

template<class T>
struct AVLTreeNode
{
	AVLTreeNode(const T& data)
	: _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
	, _data(data), _bf(0)
	{}
	AVLTreeNode<T>* _pLeft; // 该节点的左孩子
	AVLTreeNode<T>* _pRight; // 该节点的右孩子
	AVLTreeNode<T>* _pParent; // 该节点的双亲
	T _data;
	int _bf; // 该节点的平衡因子
};

AVL树的插入

  1. 按照二叉搜索树的方式插入新节点
    在这里插入图片描述
  2. 调整节点的平衡因子
    在这里插入图片描述

AVL树的旋转

  1. 新节点插入较高左子树的左侧—左左:右单旋
    在这里插入图片描述

  2. 新节点插入较高右子树的右侧—右右:左单旋

  3. 新节点插入较高左子树的右侧—左右:先左单旋再右单旋
    在这里插入图片描述

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

总结:
假如以pParent为根的子树不平衡,即pParent的平衡因子为2或者-2,分以下情况考虑

  1. pParent的平衡因子为2,说明pParent的右子树高,设pParent的右子树的根为pSubR
    当pSubR的平衡因子为1时,执行左单旋
    当pSubR的平衡因子为-1时,执行右左双旋
  2. pParent的平衡因子为-2,说明pParent的左子树高,设pParent的左子树的根为pSubL
    当pSubL的平衡因子为-1是,执行右单旋
    当pSubL的平衡因子为1时,执行左右双旋
    旋转完成后,原pParent为根的子树个高度降低,已经平衡,不需要再向上更新。

模拟avl tree的插入

#include<iostream>
#include<stack>
using namespace std;

template<class Type>
class AVLTree;

//avl node
template<class Type>
class AVLNode
{
	friend class AVLTree<Type>;
public:
	AVLNode(Type d = Type(), AVLNode<Type>*left = nullptr, AVLNode<Type>*right = nullptr)
		: data(d), leftChild(left), rightChild(right), bf(0)
	{}
	~AVLNode()
	{}
private:
	Type data;
	AVLNode<Type> *leftChild;
	AVLNode<Type> *rightChild;
	int            bf; //平衡因子
};

//avl tree
template<class Type>
class AVLTree
{
public:
	AVLTree() :root(nullptr)
	{}
public:
	bool Insert(const Type &x)
	{
		return Insert(root, x);
	}
	bool Remove(const Type &key)
	{
		return Remove(root, key);
	}
protected:
	bool Insert(AVLNode<Type> *&t, const Type &x);
	bool Remove(AVLNode<Type> *&t, const Type &key);
	void RotateR(AVLNode<Type> *&ptr);
	void RotateLR(AVLNode<Type> *&ptr);
	void RotateL(AVLNode<Type> *&ptr);
	void RotateRL(AVLNode<Type> *&ptr);
private:
	AVLNode<Type> *root;
};

//1 调整平衡  2更改bf
template<class Type>
void AVLTree<Type>::RotateR(AVLNode<Type> *&ptr)
{
	AVLNode<Type> *subR = ptr;
	ptr = subR->leftChild;

	subR->leftChild = ptr->rightChild;
	ptr->rightChild = subR;

	ptr->bf = subR->bf = 0;
}

template<class Type>
void AVLTree<Type>::RotateLR(AVLNode<Type> *&ptr)
{
	AVLNode<Type> *subL = ptr->leftChild;
	AVLNode<Type> *subR = ptr;
	ptr = subL->rightChild;

	subL->rightChild = ptr->leftChild;
	ptr->leftChild = subL;
	//更新 subL->bf
	if (ptr->bf <= 0)
		subL->bf = 0;
	else
		subL->bf = -1;

	subR->leftChild = ptr->rightChild;
	ptr->rightChild = subR;
	//更新 subR->bf
	if (ptr->bf >= 0)
		subR->bf = 0;
	else
		subR->bf = 1;

	ptr->bf = 0;
}

template<class Type>
void AVLTree<Type>::RotateL(AVLNode<Type> *&ptr)
{
	AVLNode<Type> *subL = ptr;
	ptr = subL->rightChild;
	subL->rightChild = ptr->leftChild;
	ptr->leftChild = subL;

	ptr->bf = subL->bf = 0;
}

template<class Type>
void AVLTree<Type>::RotateRL(AVLNode<Type> *&ptr)
{
	AVLNode<Type> *subL = ptr;
	AVLNode<Type> *subR = ptr->rightChild;
	ptr = subR->leftChild;

	subR->leftChild = ptr->rightChild;
	ptr->rightChild = subR;
	//更新subR->bf
	if (ptr->bf >= 0)
		subR->bf = 0;
	else
		subR->bf = 1;

	subL->rightChild = ptr->leftChild;
	ptr->leftChild = subL;
	//更新subL->bf
	if (ptr->bf == 1)
		subL->bf = -1;
	else
		subL->bf = 0;

	ptr->bf = 0;
}

template<class Type>
bool AVLTree<Type>::Insert(AVLNode<Type> *&t, const Type &x)
{
	//1 按照BST的规则插入节点
	AVLNode<Type> *pr = nullptr;
	AVLNode<Type> *p = t;

	stack<AVLNode<Type>*> st;

	while (p != nullptr)
	{
		//用于查找x的插入位置
		if (x == p->data)
			return false;

		pr = p;
		st.push(pr);

		if (x < p->data)
			p = p->leftChild;
		else
			p = p->rightChild;
	}
	p = new AVLNode<Type>(x);
	if (pr == nullptr)
	{
		t = p;
		return true;
	}

	//链接新建节点
	if (x < pr->data)
		pr->leftChild = p;
	else
		pr->rightChild = p;

	//2 如果发生不平衡,需要调整平衡
	while (!st.empty())
	{
		pr = st.top();
		st.pop();
		if (p == pr->leftChild)
			pr->bf--;
		else
			pr->bf++;

		if (pr->bf == 0)
			break;
		if (pr->bf == 1 || pr->bf == -1) // |bf| == 1 向上回溯
			p = pr;
		else
		{
			//|bf| == 2 发生不平衡 调整平衡
			if (p == pr->leftChild) //左分支
			{
				if (p->bf < 0)    //     /
				{
					RotateR(pr);
					//cout<<"RotateR."<<endl;
				}
				else            //     <
				{
					RotateLR(pr);
					//cout<<"RotateLR."<<endl;
				}
			}
			else  //右分支
			{
				if (p->bf > 0)    //   \ 
				{
					RotateL(pr);
					//cout<<"RotateL."<<endl;
				}
				else             //   > 
				{
					RotateRL(pr);
					//cout<<"RotateRL."<<endl;
				}
			}
			break;
		}
	}

	//重新链接
	if (st.empty())
		t = pr;
	else
	{
		AVLNode<Type> *ppr = st.top();
		if (ppr->data > pr->data)
			ppr->leftChild = pr;
		else
			ppr->rightChild = pr;
	}

	return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值