高阶数据结构 —— AVL树(平衡搜索树)


前言: 普通的二叉搜索树无法保证平衡,也就是 如果有序的插入数据,会导致此二叉搜索树退化为单支,效率会打折扣,所以 有了AVL树,它是可以保证 树的平衡,对于平衡的概念后面会讲,它是怎么保证平衡的?都会讲到,并且 我们要模拟实现 AVL树。


1. AVL树的概念

AVL树就是 可以 绝对保证 平衡的 搜索树,怎么才算平衡呢?

  • 平衡:左右子树的高度差 不超过 1。
  • AVL树的左右子树都是 AVL树

如何控制 平衡呢?我这里实现用的是平衡因子。也就是说 每个节点都有平衡因子。
平衡因子规则:

  • 每个节点 默认的平衡因子为 0
  • 节点的平衡因子 = 右子树高度 - 左子树高度

这就能控制平衡了?当然不能,平衡因子是用于 判断 需不需要旋转 的依据。对,是通过旋转来控制平衡的。旋转有 左单旋,右单旋 ,左右双旋,右左双旋转。听起来复杂,没事 会 理清楚的。

插入节点 平衡因子更新规则:

  • 新的节点A 插入到 节点B的右边,那么B的平衡因子+ 1
  • 新的节点A 插入到 节点B的左边,那么A的平衡因子 - 1
  • 插入节点 会 影响 此条路径上的所有祖先
  • 插入节点 后,祖先的平衡因子 可能出现 5 种情况:
    (1) 祖先的平衡因子变为 0,说明 它原来的平衡因子是 -1 \ 1 。-1 -> 0,说明是插入到它的右边, 1 -> 0, 说明插入到了它的左边;这个时候 就不需要 往上继续更新了,因为 它不可影响到 其他祖先,它很平衡。
    (2) 祖先的平衡因子变为 1,-1 。说明 它原来的平衡因子 是 0。0 -> -1,说明是插入到它的左边,0 -> 1,说明是插入到它的右边;这个时候 需不需要 往上更新,需要的,因为 它 影响了 其他祖先。更新到 没有祖先 或者 祖先的平衡因子为 0,就不往上更新了。
    (3)祖先的平衡因子变为 2/ -2 ,说明 它原来的平衡因子是 1 \ -1。1 -> 2,说明是插入到它的右边。-1 -> -2,说明是插入到它的左边。这个时候就出问题了,因为不平衡了,高度差 超过 1了,所以 要旋转。

2. 旋转 —— 乾坤大挪移

2.1 左单旋

  • 先看这颗抽象树:
    在这里插入图片描述

a,b,c 都是 子树,h代表树的高度, 3 和 6 的平衡因子给出了已经,就是 右子树高度 - 左子树高度。

那么我有个问题:在哪里插入一个节点会 引发 左单旋 ?

  • 首先,在 a 子树 下插入 会 导致 左单旋吗?肯定不会,因为 在 a 下插入节点 会导致 3 节点的平衡因子 变为 0。
  • 然后,在 b 子树 下插入,6 节点 的平衡因子 变为 -1,3 节点 受影响吗?肯定受影响,3 节点的平衡因子 变为 2。但是需要注意 这不是 左单旋转可以解决的,因为 插入的节点 对于 6 来说 是插入在了它的左边,它的平衡因子减去 1,对于 3 来说 是它的右树 新增了 一个节点 它的平衡因子 加 1。先不讲 这个情况。
  • 最后是 在 c子树 下插入,6 节点 的平衡因子 变为 1,3 节点的平衡因子 变为 2。这就需要左单旋转。

在这里插入图片描述

所以 左单旋 的平衡因子条件:

  • 出问题的节点 平衡因子 为 2,它的右子树平衡因子为 1。
  • 出问题的节点 右子树 比 左子树 高,所以 要让 此树 的 左子树 高度 +1 。

在这里插入图片描述

口诀: 右边单纯高,左单旋

  • 将出问题的节点 (3节点)往下压 ,它的 右子树(6节点) 变为 它原来的右子树(6节点)的左子树(b子树)。
  • 出问题的节点(3节点),变为 它的原来的右子树(6节点) 的左子树。

图解:
在这里插入图片描述
在这里插入图片描述

就这样 完成 左单旋,但是有人会问:你怎么知道?上面的 6节点的 左子树可以 做3节点的 右子树?还有 3节点 可以作为 6节点的 左子树。

这就是 二叉搜索树呀。

  • 第一个问题:6节点的 左子树节点 绝对比 3节点 要大,因为 插入 的时候 比 3 大插入到它的右子树,所以 3节点 的右子树 中所有的节点 都是要大于 3节点的。
  • 第二个问题:6节点是 3节点的右子树,所以 3节点 小于 6节点,所以 3节点可以作为 6节点 的 左子树。

总结: 右边单纯高,左单旋,本质就是 这颗树整体的高度 减一,去弥补 左子树。再直白点就是 让出问题的节点 下去,填补左子树,从而达到平衡。


2.2 右单旋

其实 就是 上面的例子反一下,不会讲的很细。但是 逻辑还在。

在这里插入图片描述
在 a子树下插入 会导致 右单旋转:

在这里插入图片描述

很明显,6节点 的平衡因子为 -2,需要旋转。

所以 右单旋 的平衡因子条件:

  • 出问题的节点 平衡因子 为 -2,它的左子树平衡因子为 -1。
  • 出问题的节点 左子树 比 右子树 高,所以 要让 此树 的 右子树 高度 +1。

口诀: 左边单纯高,右单旋

  • 将出问题的节点 (6节点)往下压 ,它的 左子树(3节点) 变为 它原来的左子树(3节点)的右子树(b子树)。
  • 出问题的节点(6节点),变为 它原来的左子树(3节点) 的右子树。

图解:

在这里插入图片描述
在这里插入图片描述

这就是 右单选。


2.3 右左双旋

在这里插入图片描述

这个其实用 具体点的图 好讲,因为 它得先右旋一下,再左旋一下,比较复杂,所以 我给出三种具像图:

1. h 为 0,也就是 高度为 0。

在这里插入图片描述
(1)先对 平衡因子 为-1 的节点 (6节点) ,进行右单旋
在这里插入图片描述
可以看到,先在是什么情况?平衡因子出问题的是 2,它的右子树平衡因子是1。单纯的右边高,所以要怎么办?左单旋。

(2) 再对 平衡因子 为 2 的节点 ,进行左单旋

在这里插入图片描述

2. h = 1的情况

在这里插入图片描述
那么现在 新插入的节点 插入到 5节点 的左边或者右边 都会造成 右左双旋

在这里插入图片描述

那么 对 6节点先进行右单旋:

在这里插入图片描述
再对 3节点 进行 左单旋:

在这里插入图片描述

3. 当 h=2 的情况

这种情况就多了,但是我只以一种为例子:

在这里插入图片描述
(1) 对 6进行 右单旋:

在这里插入图片描述
(2) 对 3节点 进行 左单旋

在这里插入图片描述

总结一下:我们 抽像的想一下

在这里插入图片描述
这个左右双旋,无非就是将 b这颗子树 的根节点 推上去 成为 3节点和6节点 的根,然后 将 b子树 的左子树 分给 3节点,右子树 分给 6节点。就类似这样:

在这里插入图片描述
就是 推上去,再瓜分掉其左右子树。这确实有点抽象。

说说结论:先对 出现问题的节点的右子树 进行 右单旋,再对出现问题的节点 进左单旋。当然 平衡因子这里有细节,实现的时候,我们再讲。


2.4 左右双旋

在这里插入图片描述
这种情况就需要 左右双旋:

图解如下:
(1) 先 对3节点 进行 左单旋

在这里插入图片描述
(2) 再 对6节点 进行右单旋

在这里插入图片描述

就是这样,完成了 左右双旋。


2.5 对旋转的总结

什么时候需要旋转?当出现 平衡因子 为 2或者 -2 时。

  • 左单旋:出现问题的节点 的平衡因子 为 2,它的右子树 平衡因子 为 1。本质 :新增的节点 单纯的使得 右树增高。
  • 右左双旋 :出现问题的节点 的平衡因子 为 2,它的右子树 平衡因子 为 -1。本质:新增的节点 对于平衡因子为2 来说 它是插入到右树,但是对于平衡因子 为 -1,它是插入到了 左边。
  • 右单旋:出现问题的节点 的平衡因子为 -2,它的左子树 平衡因子为 -1。本质:新增的节点 单纯的使得 左树增高。
  • 左右双旋:出现问题的节点 的平衡因子 为 -2,它的左子树 平衡因子为 1。本质:新增的节点 对于平衡因子为-2的来说,它是插入到了左树,但是对于平衡因子为 1的来说,它是插入到了 右树。

就这些情况,上面 一 一 对应的 都讲到了,只是理论实现,我们下面进行实践。


3. AVL树的实现

3.1 AVL树的 节点

template<class K, class V>
	struct AVL_node
	{
		AVL_node<K, V>* left_;
		AVL_node<K, V>* right_;
		AVL_node<K, V>* parents_;
		std::pair<K, V> kv_;

		int ef_; //Equilibrium factor 平衡因子

		AVL_node(const std::pair<K, V>& kv)
			:left_(nullptr),
			right_(nullptr),
			parents_(nullptr),
			kv_(kv),
			ef_(0)
		{}
	};

用三叉链来 实现 AVL树:

在这里插入图片描述

有指向左树的指针,右树的指针;指向父亲的指针;它的节点数据 是一个 pair<K,V>,当然还有 平衡因子 ef_。


3.2 AVL树的私有成员以及构造

AVL树 只需要记录根节点,就可以了。构造也很简单。

template<class K,class V>
	class AVL_tree
	{
		typedef AVL_node<K,V> Node;
	private:
		Node* _root;
	public:
		AVL_tree()
			:_root(nullptr)
		{}
	};

3.3 AVL树的插入

这是重点,首先 AVL树是一个搜索树,所以得遵循搜索树的逻辑去 插入节点 ;其次 我们要更新平衡因子;然后根据 平衡因子 来判断 需不要 旋转。对于平衡因子的更新,以及 是否要旋转 ,上文都有讲解。

public:
        bool insert(const std::pair<K,V>& node)
		{
			if (_root == nullptr)
			{
				_root = new Node(node);
				return true;
			}
			
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (node.first > cur->kv_.first)
				{
					parent = cur;
					cur = cur->right_;
				}
				else if (node.first< cur->kv_.first)
				{
					parent = cur;
					cur = cur->left_;
				}
				else
				{
					assert(false);
				}
			}
			cur = new Node(node);
			if (parent->kv_.first > cur->kv_.first)
			{
				parent->left_ = cur;
				cur->parents_ = parent;
			}
			else
			{
				parent->right_ = cur;
				cur->parents_ = parent;
			}
			/ 控制平衡
			 更新平衡因子
			while (parent)
			{
				if (cur == parent->left_)
				{
					parent->ef_--;
				}
				else
				{
					parent->ef_++;
				}

				if (parent->ef_ == 0)
					break;
				else if (parent->ef_ == 1 || parent->ef_ == -1)
				{
					继续往上更新 平衡因子
					cur = parent;
					parent = cur->parents_;
				}
				else if (parent->ef_ == 2 || parent->ef_ == -2)
				{
					//  旋转
					if (parent->ef_ == 2 && parent->right_->ef_ == 1)
					{
						// 左单旋转
						revolov_L(parent);

					}
					else if (parent->ef_ == 2 && parent->right_->ef_ == -1)
					{
						/// 右左双旋
						revolov_RL(parent);

					}
					else if (parent->ef_ == -2 && parent->left_->ef_ == -1)
					{
						 右单旋
						revolov_R(parent);
					}
					else if (parent->ef_ == -2 && parent->right_->ef_ == 1)
					{
						/// 左右双旋
						revolov_LR(parent);
					}
					else
					{
						assert(false);
					}
					break;
				}
			}
		}
3.3.1 左单旋代码实现

在这里插入图片描述

issue 就是 问题,英文翻译一锤。还有那个 issue_node_parent 有三种情况:

  • 为空,说明 issue_node 是根节点
  • issue_node 可能 连接在 issue_node_parent 的左边
  • issue_node 可能 连接在 issue_node_parent 的右边

这种情况 就是 左单旋:

        void revolov_L(Node* issue_node)
		{
			Node* issue_Rnode = issue_node->right_;
			Node* issue_Rnode_L = issue_Rnode->left_;
			Node* issue_node_parent = issue_node->parents_;
            
			issue_node->right_ = issue_Rnode_L;
			if (issue_Rnode_L)
			{
				issue_Rnode_L->parents_ = issue_node;
			}

			issue_Rnode->left_ = issue_node;
			issue_node->parents_ = issue_Rnode;

			if (issue_node_parent == nullptr)
			{
				_root = issue_Rnode;
				issue_Rnode->parents_ = nullptr;
			}
			else
      	    {
				if (issue_node_parent->left_ == issue_node)
					issue_node_parent->left_ = issue_Rnode;
				else
					issue_node_parent->right_ = issue_Rnode;
				issue_Rnode->parents_ = issue_node_parent;
			}

			issue_node->ef_ = issue_Rnode->ef_ = 0;
		}

其实 旋转的关键 就是在于 改变 三叉链的 链接关系。

代码结合 图解:
(1)

            issue_node->right_ = issue_Rnode_L;
            // 判读是否为空
			if (issue_Rnode_L)
			{
				issue_Rnode_L->parents_ = issue_node;
			}

在这里插入图片描述
(2)

            issue_Rnode->left_ = issue_node;
			issue_node->parents_ = issue_Rnode;
            // 改变 issue_Rnode 的 parents
			if (issue_node_parent == nullptr)
			{
				_root = issue_Rnode;
				issue_Rnode->parents_ = nullptr;
			}
			
			else
      	    {
				if (issue_node_parent->left_ == issue_node)
					issue_node_parent->left_ = issue_Rnode;
				else
					issue_node_parent->right_ = issue_Rnode;
				issue_Rnode->parents_ = issue_node_parent;
			}

在这里插入图片描述
就是这样式的,最后 更新一下 平衡因子 就 OK了。


3.3.2 右单旋代码实现

在这里插入图片描述

       void revolov_R(Node* issue_node)
		{
			Node* issue_Lnode = issue_node->left_;
			Node* issue_Lnode_R = issue_Lnode->right_;
			Node* issue_node_parent = issue_node->parents_;

			issue_node->left_ = issue_Lnode_R;
			if (issue_Lnode_R)
			{
				issue_Lnode_R->parents_ = issue_node;
			}

			issue_Lnode->right_ = issue_node;
			issue_node->parents_ = issue_Lnode;

			if (issue_node_parent == nullptr)
			{
				_root = issue_Lnode;
				issue_Lnode->parents_ = nullptr;
			}
			else
			{
				if (issue_node_parent->left_ == issue_node)
					issue_node_parent->left_ = issue_Lnode;
				else
					issue_node_parent->right_ = issue_Lnode;
				issue_Lnode->parents_ = issue_node_parent;
			}

			issue_node->ef_ = issue_Lnode->ef_ = 0;
		}

这就是 和上面 反一下,逻辑一样的。


3.3.3 右左双旋代码实现

在这里插入图片描述

        void revolov_RL(Node* issue_node)
		{
			revolov_R(issue_node->right_);
			revolov_L(issue_node);
		}

3.3.4 左右双旋代码实现

在这里插入图片描述

        void revolov_LR(Node* issue_node)
		{
			revolov_L(issue_node->left_);
			revolov_R(issue_node);
		}

3.4 AVL树的中序遍历

我们都知道 搜索树 的中序遍历就是 有序的。所以 可以用来 先验证 一下 我们上面 实现的 AVL树是否为 搜索树。

        public:
		void InOrder()
		{
			_InOrder(_root);
		}

		private:
		void _InOrder(Node* root)
		{
			if (root == NULL)
				return;

			_InOrder(root->left_);
			std::cout << root->kv_.first << ":" << root->kv_.second << std::endl;
			_InOrder(root->right_);
		}

好,现在 我们 来验证一下:

int main()
{
	
	
	AVL_tree<int, int> t;
	//int a[] = {5,4,3,2,1,0};
	//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	for (auto e : a)
	{
		t.insert(std::make_pair(e, e));
	}
	t.InOrder();
	return 0;
}

运行结果:

在这里插入图片描述
没问题 就是 搜索树。


3.5 AVL树 验证 平衡

验证平衡的关键 就是 :左右子树的差值 ,是否 与平衡因子 相等。

有人说:直接 查看 平衡因子就行了,这是不可以的,因为平衡因子 是由我们来控制的,它不一定能 反馈真实情况。

        public:
		bool IsBalance()
		{
			return _IsBalance(_root);
		}
		private:
		int Height(Node* root)
		{
			if (root == NULL)
				return 0;
			int leftHeight = Height(root->left_);
			int rightHeight = Height(root->right_);
			return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
		}

		bool _IsBalance(Node* root)
		{
			if (root == NULL)
				return true;

			// 对当前树进行检查
			int leftHeight = Height(root->left_);
			int rightHeight = Height(root->right_);

			if (rightHeight - leftHeight != root->ef_)
			{
			std:: cout << root->kv_.first << "现在是:" << root->ef_ << std::endl;
			std:: cout << root->kv_.first << "应该是:" << rightHeight - leftHeight << std::endl;
				return false;
			}

			return abs(rightHeight - leftHeight) < 2
				&& _IsBalance(root->left_)
				&& _IsBalance(root->right_);
		}

好,验证一下是否平衡:

int main()
{
	AVL_tree<int, int> t;
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	for (auto e : a)
	{
		t.insert(std::make_pair(e, e));
		std::cout << "Insert" << e << ":" << t.IsBalance() << std::endl;
	}
	return 0;
}

在这里插入图片描述
发现 插入 14 的时候,导致 6节点 的平衡因子 出错了,平衡因子有问题 绝对会影响 后序的插入。

这是为什么呢?

在这里插入图片描述
插入 14节点,会怎样? 右左双旋

先对 15节点 右单旋
在这里插入图片描述
再对 6 进行 左单旋转

在这里插入图片描述

6节点 的平衡因子 是 -1,但是 因为 对它进行了 左单旋,将它的平衡因子 置成了 0。这就是问题所在,所以双旋需要控制平衡因子,怎么控制呢?

3.5.1 控制双旋的平衡因子
3.5.1.1 右左双旋

在这里插入图片描述
其实这块,可以翻上去 看看 我画的 那三种情况:

旋转完后, 6 的平衡因子 有两种情况 :

  • 6 的平衡因子为 0,h为 0,所以 b是新增节点
  • 6 的平衡因子为 1,说明 新增的节点 是 b树的 左边
    旋转完后,3 的平衡因子 有两种情况:
  • 3 的平衡因子为 0,h为 0,所以 b是新增节点
  • 3 的平衡因子为 -1,说明 新增的节点是 b树的 右边

总结一下:出问题的节点 双旋完之后,它的平衡因子 必然为0;关键就是 那个平衡因子为 -1的节点,双旋完后,它的平衡因子需要控制,它的平衡因子控制看的是 b树的情况。

我还是 画画 图吧。
(1) 第一种情况,这个比较简单

在这里插入图片描述
(2) 新增节点在 b树的右边

在这里插入图片描述
(3) 新增节点在 b树的左边

在这里插入图片描述

从这其实 也能再次抽象 理解 :

将 那个新增节点的根节点,推上去作为此支树的根,然后让出问题的节点和问题节点的右树瓜分它的 左子树和右子树。 没瓜分到的 所以就会 导致 平衡因子 为 1或者 -1。

代码实现:

        void revolov_RL(Node* issue_node)
		{
			Node* issue_Rnode = issue_node->right_;
			Node* issue_Rnode_L = issue_Rnode->left_;
			int flag = 0;
			if (issue_Rnode_L->ef_ == 1)
			{
				flag = 1;
			}
			if (issue_Rnode_L->ef_ == -1)
			{
				flag = -1;
			}
			revolov_R(issue_Rnode);
			revolov_L(issue_node);

			if (flag == 1)
			{
				issue_node->ef_ = -1;
			}
			if (flag == -1)
			{
				issue_Rnode->ef_ = 1;
			}
			
		}

昂,再来 验证一下上面那个 平衡:
在这里插入图片描述
这就解决问题了。


3.5.1.2 左右双旋

在这里插入图片描述

有了上面的基础,其实 左右双旋也是可以实现的,主要是 看 b树情况:

只不过就反一下而已,我直接画图:

(1)
在这里插入图片描述
(2)
在这里插入图片描述
(3)
在这里插入图片描述

代码实现:

        void revolov_LR(Node* issue_node)
		{
			Node* issue_Lnode = issue_node->left_;
			Node* issue_Lnode_R = issue_Lnode->right_;
			int flag = 0;
			if (issue_Lnode_R->ef_ == 1)
			{
				flag = 1;
			}
			if (issue_Lnode_R->ef_ == -1)
			{
				flag = -1;
			}

			revolov_L(issue_node->left_);
			revolov_R(issue_node);

			if (flag == 1)
			{
				issue_Lnode->ef_ = -1;
			}

			if (flag == -1)
			{
				issue_node->ef_ = 1;
			}
		}

就是这样,大家下去好好思考。


4. AVL树 代码汇总

#pragma once

#include<iostream>
#include<assert.h>

namespace AVL
{
	template<class K, class V>
	struct AVL_node
	{
		AVL_node<K, V>* left_;
		AVL_node<K, V>* right_;
		AVL_node<K, V>* parents_;
		std::pair<K, V> kv_;

		int ef_; //Equilibrium factor 平衡因子

		AVL_node(const std::pair<K, V>& kv)
			:left_(nullptr),
			right_(nullptr),
			parents_(nullptr),
			kv_(kv),
			ef_(0)
		{}
	};

	template<class K,class V>
	class AVL_tree
	{
		typedef AVL_node<K,V> Node;
	private:
		Node* _root;
	public:
		AVL_tree()
			:_root(nullptr)
		{}
	private:
		void revolov_L(Node* issue_node)
		{
			Node* issue_Rnode = issue_node->right_;
			Node* issue_Rnode_L = issue_Rnode->left_;
			Node* issue_node_parent = issue_node->parents_;

			issue_node->right_ = issue_Rnode_L;
			if (issue_Rnode_L)
			{
				issue_Rnode_L->parents_ = issue_node;
			}

			issue_Rnode->left_ = issue_node;
			issue_node->parents_ = issue_Rnode;

			if (issue_node_parent == nullptr)
			{
				_root = issue_Rnode;
				issue_Rnode->parents_ = nullptr;
			}
			else
      	    {
				if (issue_node_parent->left_ == issue_node)
					issue_node_parent->left_ = issue_Rnode;
				else
					issue_node_parent->right_ = issue_Rnode;
				issue_Rnode->parents_ = issue_node_parent;
			}

			issue_node->ef_ = issue_Rnode->ef_ = 0;
		}

		void revolov_R(Node* issue_node)
		{
			Node* issue_Lnode = issue_node->left_;
			Node* issue_Lnode_R = issue_Lnode->right_;
			Node* issue_node_parent = issue_node->parents_;

			issue_node->left_ = issue_Lnode_R;
			if (issue_Lnode_R)
			{
				issue_Lnode_R->parents_ = issue_node;
			}

			issue_Lnode->right_ = issue_node;
			issue_node->parents_ = issue_Lnode;

			if (issue_node_parent == nullptr)
			{
				_root = issue_Lnode;
				issue_Lnode->parents_ = nullptr;
			}
			else
			{
				if (issue_node_parent->left_ == issue_node)
					issue_node_parent->left_ = issue_Lnode;
				else
					issue_node_parent->right_ = issue_Lnode;
				issue_Lnode->parents_ = issue_node_parent;
			}

			issue_node->ef_ = issue_Lnode->ef_ = 0;
		}

		void revolov_RL(Node* issue_node)
		{
			Node* issue_Rnode = issue_node->right_;
			Node* issue_Rnode_L = issue_Rnode->left_;
			int flag = 0;
			if (issue_Rnode_L->ef_ == 1)
			{
				flag = 1;
			}
			if (issue_Rnode_L->ef_ == -1)
			{
				flag = -1;
			}
			revolov_R(issue_Rnode);
			revolov_L(issue_node);

			if (flag == 1)
			{
				issue_node->ef_ = -1;
			}
			if (flag == -1)
			{
				issue_Rnode->ef_ = 1;
			}
			
		}

		void revolov_LR(Node* issue_node)
		{
			Node* issue_Lnode = issue_node->left_;
			Node* issue_Lnode_R = issue_Lnode->right_;
			int flag = 0;
			if (issue_Lnode_R->ef_ == 1)
			{
				flag = 1;
			}
			if (issue_Lnode_R->ef_ == -1)
			{
				flag = -1;
			}

			revolov_L(issue_node->left_);
			revolov_R(issue_node);

			if (flag == 1)
			{
				issue_Lnode->ef_ = -1;
			}

			if (flag == -1)
			{
				issue_node->ef_ = 1;
			}
		}



	public:
		bool insert(const std::pair<K,V>& node)
		{
			if (_root == nullptr)
			{
				_root = new Node(node);
				return true;
			}
			
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (node.first > cur->kv_.first)
				{
					parent = cur;
					cur = cur->right_;
				}
				else if (node.first< cur->kv_.first)
				{
					parent = cur;
					cur = cur->left_;
				}
				else
				{
					assert(false);
				}
			}
			cur = new Node(node);
			if (parent->kv_.first > cur->kv_.first)
			{
				parent->left_ = cur;
				cur->parents_ = parent;
			}
			else
			{
				parent->right_ = cur;
				cur->parents_ = parent;
			}
			/ 控制平衡
			 更新平衡因子
			while (parent)
			{
				if (cur == parent->left_)
				{
					parent->ef_--;
				}
				else
				{
					parent->ef_++;
				}

				if (parent->ef_ == 0)
					break;
				else if (parent->ef_ == 1 || parent->ef_ == -1)
				{
					继续往上更新 平衡因子
					cur = parent;
					parent = cur->parents_;
				}
				else if (parent->ef_ == 2 || parent->ef_ == -2)
				{
					//  旋转
					if (parent->ef_ == 2 && parent->right_->ef_ == 1)
					{
						// 左单旋转
						revolov_L(parent);

					}
					else if (parent->ef_ == 2 && parent->right_->ef_ == -1)
					{
						/// 右左双旋
						revolov_RL(parent);

					}
					else if (parent->ef_ == -2 && parent->left_->ef_ == -1)
					{
						 右单旋
						revolov_R(parent);
					}
					else if (parent->ef_ == -2 && parent->right_->ef_ == 1)
					{
						/// 左右双旋
						revolov_LR(parent);
					}
					else
					{
						assert(false);
					}
					break;
				}
			}
		}

		
		public:
		void InOrder()
		{
			_InOrder(_root);
		}

		private:
		void _InOrder(Node* root)
		{
			if (root == NULL)
				return;

			_InOrder(root->left_);
			std::cout << root->kv_.first << ":" << root->kv_.second << std::endl;
			_InOrder(root->right_);
		}
		
		public:
		bool IsBalance()
		{
			return _IsBalance(_root);
		}
		private:
		int Height(Node* root)
		{
			if (root == NULL)
				return 0;
			int leftHeight = Height(root->left_);
			int rightHeight = Height(root->right_);
			return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
		}

		bool _IsBalance(Node* root)
		{
			if (root == NULL)
				return true;

			// 对当前树进行检查
			int leftHeight = Height(root->left_);
			int rightHeight = Height(root->right_);

			if (rightHeight - leftHeight != root->ef_)
			{
			std:: cout << root->kv_.first << "现在是:" << root->ef_ << std::endl;
			std:: cout << root->kv_.first << "应该是:" << rightHeight - leftHeight << std::endl;
				return false;
			}

			return abs(rightHeight - leftHeight) < 2
				&& _IsBalance(root->left_)
				&& _IsBalance(root->right_);
		}
	};
}

5.结尾

以上就是 AVL树 的实现,有问题 的私信,或者评论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

动名词

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值