STL容器之map和set的补充——AVL树

一、AVL树

​ 不同搜索的对比:1.暴力搜索时间复杂度是O(N);2.二分查找的时间复杂度是O(lgN),但是伴随着有序,插入删除挪动数据的成本极高;3.二叉搜索的时间复杂度是高度次数,极端场景会退化为类似链表时间复杂度是O(N)/O(lgN);4.平衡二叉搜索树;5.多叉平衡搜素树;6.哈希表快速搜索;

​ 平衡二叉搜索树有avl树和红黑树;

1.1概念

​ AVL树又叫做高度平衡二叉搜索树;

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

​ AVL树要不是空树,要不然就是:1.左右子树都是AVL树,平衡因子(右子树高度减去左子树高度)的绝对值小于等于1;

​ 满二叉树就是最平衡的AVL树;

1.2AVL树的模拟实现

1.2.1插入原理

在这里插入图片描述

先创建搜索二叉树,然后更新平衡因子,然后解决平衡错误(旋转解决);

​ 1.左子树插入会使得父亲的平衡因子–,右子树会使得父亲的平衡因子++,平衡因子只会影响祖先;

​ 2.平衡因子变为0,说明树的高度没有发生变化,其他祖先的平衡因子不需要发生变化,变为正负一才需要,沿着祖先路径,parent和cur向上调整;

​ 3.插入一个节点是平衡因子默认就是0;

​ 4.若平衡因子是2或者-2,就不平衡了,需要旋转,旋转要注意:1.保持子树是搜索树;2.变成平衡树且降低整棵树的高度;即左单旋,对于右子树过高,向左旋转,使得parent->right=cur->left,cur->left=parent,强行让parent 节点向下走一截,旋转之后的高度相较于插入之前是没有变化的。在旋转的过程中除了更新平衡因子,还需要更新parent_。右单旋类似;

​ 5更新到平衡因子为0或者旋转结束或者更新到根节点就插入结束;

旋转原理:插入前平衡因子是1/-1;

在这里插入图片描述

h是子树的高度,h是1或者0和之前是一样的,如果h是2,则a、b子树可以是:

在这里插入图片描述

在这里插入图片描述

但是c只能是第三种,因为第1和第2种都不会影响到30和60节点的平衡因子;一共有36种可能的插入情况。即无法穷尽,但是核心规则是不变的。

双旋

​ 当parent与cur的平衡因子为异号时,即是折线就是双旋,否则就是直线单旋;

右左双旋:

在这里插入图片描述

​ h=0,就是简单的直线;h=1,就是在60的左右叶子节点插入都会使得parent异常;h=2,a和d可以是上述任意三种情况,bc是一个节点。

​ 先90为旋转点进行右旋,然后30为旋转点进行左旋。即第一次旋转变成直线,左单旋,第二次单旋变成平衡。要注意双旋之后要更新平衡因子。

​ 观察发现双旋的结果本质就是60的左给30,右给90并且30,90,做了60的左右。

​ 更新平衡因子分三种情况,1、插入元素后,对于30、60、90,60的平衡因子为-1,说明在60的左子树插入,最终会使得60的右的平衡因子为1,其他为0;2、60平衡因子为1,则60左的平衡因子为-1;3、60的平衡因子为0,则60左右的平衡因子为0。

​ 但是双旋存在问题。学会使用自己写一个辅助程序帮助调试。对于循环可以if等于具体的值来打断点调试。

#pragma once

#include <cassert>

namespace AvlTree
{
	template <class K, class V>
	struct AVLTreeNode
	{
		// 构造函数
		AVLTreeNode(const pair<K, V> kv) : kv_(kv), left_(nullptr), right_(nullptr), parent_(nullptr), bf_(0) {}

		// 成员
		pair<K, V> kv_;
		AVLTreeNode<K, V> *left_;
		AVLTreeNode<K, V> *right_;
		AVLTreeNode<K, V> *parent_; // 三叉链便于旋转
		// 平衡因子
		int bf_;
	};
	template <class K, class V>
	class AVLTree
	{
		// 内嵌类型
		typedef AVLTreeNode<K, V> node;

	public:
		// 默认构造函数
		AVLTree() : root_(nullptr) {}

	public:
		// 普通成员函数
		void rotatel(node *parent);
		void rotater(node *parent);
		void rotaterl(node *parent);
		void rotatelr(node *parent);
		bool insert(const pair<K, V> &kv);
		int height(node *root);
		bool isavltree()
		{
			return _isavltree(root_);
		}
		void inorder()
		{
			_inorder(root_);
		}

	private:
		// 私有成员
		void _inorder(node *root);
		bool _isavltree(node *root);
		node *root_;
	};
	template <class K, class V>
	void AVLTree<K, V>::rotatel(node *parent)
	{
		node *cur = parent->right_;
		node *curleft = cur->left_;
		parent->right_ = curleft;
		node *ppnode = parent->parent_;
		if (curleft)
			curleft->parent_ = parent;
		parent->parent_ = cur;
		cur->left_ = parent;
		parent->bf_ = 0;
		cur->bf_ = 0;

		if (parent == root_)
		{
			root_ = cur;
			cur->parent_ = nullptr;
		}
		else
		{
			if (ppnode->left_ == parent)
			{
				ppnode->left_ = cur;
			}
			else
			{
				ppnode->right_ = cur;
			}
			cur->parent_ = ppnode;
		}
	}
	template <class K, class V>
	void AVLTree<K, V>::rotater(node *parent)
	{
		node *cur = parent->left_;
		node *curright = cur->right_;
		node *ppnode = parent->parent_;
		parent->left_ = curright;
		cur->right_ = parent;
		if (curright)
			curright->parent_ = parent;
		parent->parent_ = cur;
		parent->bf_ = 0;
		cur->bf_ = 0;

		if (parent == root_)
		{
			root_ = cur;
			cur->parent_ = nullptr;
		}
		else
		{
			if (ppnode->left_ == parent)
			{
				ppnode->left_ = cur;
			}
			else
			{
				ppnode->right_ = cur;
			}
			cur->parent_ = ppnode;
		}
	}
	template <class K, class V>
	void AVLTree<K, V>::rotaterl(node *parent)
	{
		// 更新平衡因子
		node *cur = parent->right_;
		node *curleft = cur->left_;
		int bf = curleft->bf_;

		rotater(parent->right_);
		rotatel(parent);
		if (bf == 0)
		{
			cur->bf_ = 0;
			curleft->bf_ = 0;
			parent->bf_ = 0;
		}
		else if (bf == -1)
		{
			cur->bf_ = 1;
			curleft->bf_ = 0;
			parent->bf_ = 0;
		}
		else if (bf == 1)
		{
			parent->bf_ = -1;
			cur->bf_ = 0;
			curleft->bf_ = 0;
		}
		else
		{
			assert(false);
		}
	}
	template <class K, class V>
	void AVLTree<K, V>::rotatelr(node *parent)
	{
		// 更新平衡因子
		node *cur = parent->left_;
		node *curright = cur->right_;
		int bf = curright->bf_;

		rotatel(parent->left_);
		rotater(parent);
		if (bf == 0)
		{
			cur->bf_ = 0;
			curright->bf_ = 0;
			parent->bf_ = 0;
		}
		else if (bf == -1)
		{
			cur->bf_ = 0;
			curright->bf_ = 0;
			parent->bf_ = 1;
		}
		else if (bf == 1)
		{
			parent->bf_ = 0;
			cur->bf_ = -1;
			curright->bf_ = 0;
		}
		else
		{
			assert(false);
		}
	}
	template <class K, class V>
	bool AVLTree<K, V>::insert(const pair<K, V> &kv)
	{
		if (root_ == nullptr)
		{
			root_ = new node(kv);
			return true;
		}
		node *cur = root_;
		node *parent = cur;
		while (cur)
		{
			if (kv.first > cur->kv_.first)
			{
				parent = cur;
				cur = cur->right_;
			}
			else if (kv.first < cur->kv_.first)
			{
				parent = cur;
				cur = cur->left_;
			}
			else
			{
				return false;
			}
		}
		cur = new node(kv);
		if (kv.first > parent->kv_.first)
		{
			parent->right_ = cur;
		}
		else
		{
			parent->left_ = cur;
		}
		cur->parent_ = parent;

		// 控制平衡,更新平衡因子
		while (parent)
		{
			if (cur == parent->left_)
			{
				parent->bf_--;
			}
			else
			{
				parent->bf_++;
			}
			if (!parent->bf_)
			{
				break;
			}
			if (parent->bf_ == 1 || parent->bf_ == -1)
			{
				cur = parent;
				parent = parent->parent_;
			}
			else if (parent->bf_ == 2 || parent->bf_ == -2)
			{
				if (parent->bf_ == 2 && cur->bf_ == 1)
				{
					// 左单旋
					rotatel(parent);
					break;
				}
				else if (parent->bf_ == -2 && cur->bf_ == -1)
				{
					// 右单旋
					rotater(parent);
					break;
				}
				else if (parent->bf_ == 2 && cur->bf_ == -1)
				{
					// 右左双旋
					rotaterl(parent);
					break;
				}
				else if (parent->bf_ == -2 && cur->bf_ == 1)
				{
					// 左右双旋
					rotatelr(parent);
					break;
				}
				else
				{
					assert(false);
				}
			}
			else
			{
				assert(parent->bf_ <= 2 && parent->bf_ >= -2);
			}
		}
		return true;
	}
	template <class K, class V>
	int AVLTree<K, V>::height(node *root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftheight = height(root->left_);
		int rightheight = height(root->right_);
		return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
	}
	template <class K, class V>
	bool AVLTree<K, V>::_isavltree(node *root)
	{
		if (root == nullptr)
		{
			return true;
		}
		int leftheight = height(root->left_);
		int rightheight = height(root->right_);
		if ((rightheight - leftheight) != root->bf_)
		{
			cout << "平衡因子异常:" << root->kv_.first << ":" << root->kv_.second << ":" << root->bf_ << endl;
			return false;
		}
		return abs(rightheight - leftheight) < 2 && _isavltree(root->left_) && _isavltree(root->right_);
	}
	template <class K, class V>
	void AVLTree<K, V>::_inorder(node *root)
	{
		if (root == nullptr)
		{
			return;
		}
		_inorder(root->left_);
		cout << root->kv_.first << ":" << root->kv_.second << endl;
		_inorder(root->right_);
	}
}
  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值