AVL(平衡二叉树)

平衡二叉树

  在二叉搜索树的基础上引入平衡因子BF(balance factor)= 右子树高度 - 左子树高度,防止出现单链接太长的情况。
AVL保证每个左子树和右子树的高度差不超过1。平衡因子的更新规则:

  • 若新增的节点在parent右边,parent->BF++;
  • 若新增的节点在parent左边,parent->BF- -;
    • 若parent的平衡因子等于1 or -1,继续往上更新
    • 若parent的平衡因子等于0,停止更新
    • 若parent的平衡因子等于2 或者 -2,开始旋转

AVL的旋转考虑四种情况:
右单旋:
在这里插入图片描述
代码:

void RotateR(Node* parent)
{
    Node* pleft = parent->_left;
    Node* pleftR = pleft->_right;
    Node* parentParent = parent->_parent;

    parent->_parent = pleft;
    pleft->_right = parent;

    if (pleftR) //Pleft_Right若为nullptr,则无法找到其parent
    {
        pleftR->_parent = parent;
    }
    parent->_left = pleftR;

    if (parent == _root) //若原来的parent为根,则将pleft更新为根节点
    {
        _root = pleft;
        _root->_parent = nullptr;
    }
    else // parent不为根节点,则其存在父节点,将pleft的父节点与原来parent的父节点进行链接
    {
        if (parentParent->_left == parent)
        {
            parentParent->_left = pleft;
        }
        else
            parentParent->_right = pleft;
        pleft->_parent = parentParent;
    }

    pleft->_BF = parent->_BF = 0;  //更新右旋后的平衡因子

}

左单旋:
在这里插入图片描述
代码:

void RotateL(Node* parent)
{
	Node* pright = parent->_right;
	Node* prightL = pright->_left;
	Node* parentParent = parent->_parent;

	parent->_parent = pright;
	pright->_left = parent;

	if (prightL)
	{
		prightL->_parent = parent;
	}
	parent->_right = prightL;

	if (parent == _root)
	{
		_root = pright;
		_root->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = pright;
		}
		else if (parentParent->_right == parent)
		{
			parentParent->_right = pright;
		}
		pright->_parent = parentParent;
	}
	pright->_BF = parent->_BF = 0;
}

左右双旋:
旋转方式:先以B为parent进行左单旋,再以A为parent进行右单旋。另外双旋需要注意平衡因子的更新情况:

  • D的平衡因子为1:
    在这里插入图片描述
  • D的平衡因子为-1
    在这里插入图片描述
  • 新增节点,D的平衡因子为0
    在这里插入图片描述
    代码:
void RotateLR(Node* parent)
{
	Node* pleft = parent->_left;
	Node* pleftR = pleft->_right;

	int BF_tmp = pleftR->_BF;

	RotateR(pleft);
	RotateL(parent);

	//更新平衡因子
	if (BF_tmp == 1)
	{
		parent->_BF = 0;
		pleft->_BF = -1;
		pleftR->_BF = 0;
	}
	else if (BF_tmp == -1)
	{
		parent->_BF = 1;
		pleft->_BF = 0;
		pleftR->_BF = 0;
	}
	else
	{
		parent->_BF = 0;
		pleft->_BF = 0;
		pleftR->_BF = 0;
	}
}

右左双旋:
旋转方式:先以B为parent进行右单旋,再以A为parent进行左单旋。

  • D的平衡因子为-1:
    在这里插入图片描述
  • D的平衡因子为1:
    在这里插入图片描述
  • D的平衡因子为0:
    在这里插入图片描述
    代码:
void RotateRL(Node* parent)
{
	Node* pright = parent->_right;
	Node* prightL = pright->_left;
		
	int BF_tmp = prightL->_BF;

	RotateR(pright);
	RotateL(parent);

	//更新平衡因子
	if (BF_tmp == 1)
	{
		parent->_BF = 0;
		pright->_BF = 1;
		prightL->_BF = 0;
	}
	else if (BF_tmp == -1)
	{
		parent->_BF = -1;
		pright->_BF = 0;
		prightL->_BF = 0;
	}
	else
	{
		parent->_BF = 0;
		pright->_BF = 0;
		prightL->_BF = 0;
	}
}

完整代码:

#pragma once
#include <iostream>
using std::pair;

template<class K, class V>
struct AVLNode {
	AVLNode<K, V>* _left;
	AVLNode<K, V>* _right;
	AVLNode<K, V>* _parent;

	int _BF;
	std::pair<K, V> _kv;

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

};

template<class K, class V>
class AVLTree {
	typedef AVLNode<K, V> Node;
public:
	AVLTree()
		:_root(nullptr)
	{}

	void RotateR(Node* parent);

	void RotateL(Node* parent);

	void RotateRL(Node* parent);

	void RotateLR(Node* parent);



	bool Insert(const pair<K, V>& kv)
	{
		Node* newnode = new Node(kv);
		Node* parent = _root;
		Node* cur = _root;

		if (_root == nullptr)
		{
			_root = newnode;
			return true;
		}

		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;
		}
		//先插入
		if (parent->_kv.first > kv.first)
		{
			parent->_left = newnode;
			newnode->_parent = parent;
		}
		else if (parent->_kv.first < kv.first)
		{
			parent->_right = newnode;
			newnode->_parent = parent;
		}
		cur = newnode;
		// 计算平衡因子
		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)
			{
				cur = parent;
				parent = parent->_parent;
			}

			else if (parent->_BF == 2 || parent->_BF == -2)
			{
				if (parent->_BF == -2)
				{
					if (cur->_BF == -1)
					{
						RotateR(parent);
					}
					else if(cur->_BF == 1)
					{
						RotateLR(parent);
					}
				}
				else // parent->_BF == 2
				{
					if (cur->_BF == 1)
					{
						RotateL(parent);
					}
					else if(cur->_BF == -1)
					{
						RotateRL(parent);
					}
				}
				break; // 双旋会将parent置0,不用再更新平衡因子了
			}
		}
	}


	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		std::cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}

	void Print()
	{
		_InOrder(_root);
	}

private:
	Node* _root;

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值