AVL树/红黑树介绍及插入操作实现

本文详细介绍了AVL树和红黑树的概念,这两种自平衡二叉搜索树能够保证查找效率。AVL树通过保持左右子树高度差不超过1来保持平衡,插入操作后可能需要进行旋转调整。红黑树则通过颜色规则确保最长路径不超过最短路径的两倍,插入操作中涉及变色和旋转操作。此外,文章还展示了如何使用AVL树和红黑树实现map和set的基本操作。

一.AVL树概念

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

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1( 可以为-1/0/1 )

在这里插入图片描述

二.AVL树模拟实现

AVL树接口总览

template<class K,class V>
struct AVLTreeNode
{
   
   
	AVLTreeNode(const pair<K,V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_bf(0)
		,_kv(kv)
	{
   
   }
	AVLTreeNode* _left; // 指向左子树节点
	AVLTreeNode* _right; // 指向右子树节点
	AVLTreeNode* _parent; // 指向父节点
	int _bf;  // 平衡因子
	pair<K, V> _kv; // 节点数据
};
template<class K,class V>
class AVLTree
{
   
   
	typedef AVLTreeNode<K, V> Node;
public:
	AVLTree()
		:_root(nullptr)
	{
   
   }
	~AVLTree();
	Node* Find(const K& key);
	V& operator[](const K& key);
	bool IsAVLTree();
	void InOrder();
	bool Insert(const pair<K, V>& kv);
	void RotateL(Node* parent);
	void RotateR(Node* parent);
	void RotateLR(Node* parent);
	void RotataRL(Node* parent);
private:
	Node* _root;
};

当插入一个新节点的时候,首先根据二叉搜索树的性质,比根节点小的去左子树查找,比根节点大的去右子树查找,循环找到新节点的位置,如果是二叉搜索树的话,插入操作到此就完成了,但AVL树需要保证平衡因子的绝对值不超过1,所以我们还需要更新 新节点沿着父节点的路径上的平衡因子,如果有绝对值超过2的平衡因子,则需要进行旋转操作

在这里插入图片描述

右单旋 :

在这里插入图片描述

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

	parent->_left = subLR;
	subL->_right = parent;
	if (subLR)
		subLR->_parent = parent;
	if (parent == _root)
	{
   
   
		_root = subL;
		_root->_parent = nullptr;
	}
	else
	{
   
   
		if (parentParent->_right == parent) parentParent->_right = subL;
		else parentParent->_left = subL;
		subL->_parent = parentParent;
	}
	parent->_parent = subL;
	subL->_bf = parent->_bf = 0;
}

左单旋 :

在这里插入图片描述

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

	parent->_right = subRL;
	subR->_left = parent;
	if (subRL)
		subRL->_parent = parent;
	if (parent == _root)
	{
   
   
		_root = subR;
		_root->_parent = nullptr;
	}
	else
	{
   
   
		if (parentParent->_right == parent) parentParent->_right = subR;
		else parentParent->_left = subR;
		subR->_parent = parentParent;
	}
	parent->_parent = subR;
	subR->_bf = parent->_bf = 0;
}

左右双旋 :

在这里插入图片描述

void RotateLR(Node* parent)
{
   
   
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;
	RotateL(subL);
	RotateR(parent);
	if (bf == 1)
	{
   
   
		parent->_bf = 0;
		subLR->_bf = 0;
		subL->_bf = -1;
	}
	else if (bf == -1)
	{
   
   
		parent->_bf = 1;
		subLR->_bf = 0;
		subL->_bf = 0;
	}
	else if (bf == 0)
	{
   
   
		parent->_bf = 0;
		subLR->_bf = 0;
		subL->_bf = 0;
	}
}

右左双旋 :

在这里插入图片描述

void RotateRL(Node* parent)
{
   
   
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int bf = subRL->_bf;
	RotateR(subR);
	RotateL(parent);
	if (bf == 1)
	{
   
   
		parent->_bf = -1;
		subR->_bf = 0;
		subRL->_bf = 0;
	}
	else if (bf == -1)
	{
   
   
		parent->_bf = 0;
		subR->_bf = 1;
		subRL->_bf = 0;
	}
	else if (bf == 0)
	{
   
   
		parent->_bf = 0;
		subR->_bf = 0;
		subRL->_bf = 0;
	}
}

插入操作

pair<Node*, bool> Insert(const pair<K, V>& kv)
{
   
   
	// 完成插入操作
	if (_root == nullptr)
	{
   
   
		_root = new Node(kv);
		return pair<Node*,bool>(_root,true);
	}
	Node* parent = _root, * cur = _root;
	while (cur)
	{
   
   
		if (kv.first < cur->_kv.first)
		{
   
   
			parent = cur;
			cur = cur->_left;
		}
		else if (kv.first > cur->_kv.first)
		{
   
   
			parent = cur;
			cur = cur->_right;
		}
		else
		{
   
   
			return pair<Node*,bool>(cur, false);
		}
	}
	cur = new Node(kv);
	if (parent->_kv.first < cur->_kv.first) parent->_right = cur;
	else parent->_left = cur;
	cur->_parent = parent;
	Node* tmp = cur;
	// 更新平衡因子
	while (cur != _root)
	{
   
   
		if (parent->_kv.first < cur->_kv.first) ++parent->_bf;
		else --parent->_bf;

		if (parent->_bf == 0) break;
		else if (parent->_bf == 1 || parent->_bf == -1)
		{
   
   
			cur = parent;
			parent = cur->_parent;
		}</
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值