浅谈AVL树


在这里插入图片描述

1.介绍

1.1定义

AVL树 – 平衡二叉树 – 平衡二叉搜索(排序)树 – 高度平衡搜索树
Balanced Binary Tree (BBT)

1.2来源

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

1.3概念

1.特性

  • 一棵空树或左右两个子树高度差绝对值不超过1
  • 左右两个子树也都是一棵高度平衡搜索树

2.平衡因子[ Balance Factor-- _bf ]

  1. 结点的平衡因子 == 右子树高度 - 左子树高度
  2. | _bf | <= 1
  3. AVL树不一定有平衡因子, 使用平衡因子只是一种较为简单的实现方式
    在这里插入图片描述

2.BST==>AVL

[设定 _bf = 右子树高度 - 左子树高度]

1.示例分析

先看一下下面的图 了解一下什么叫做旋转 以及旋转的目的

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

2.情况分类

在这里插入图片描述

3.代码剖析

3.1左左型-右单旋

在这里插入图片描述

	void RotateRight(Node* dad)
	{
		Node* Grandpa = dad->_parent;
		Node* sonL = dad->_left;
		Node* sonLR = sonL->_right;

		//dad连接sonLR sonLR不空-继承dad 为空不继承
		dad->_left = sonLR;
		if (sonLR)
			sonLR->_parent = dad;
        //sonL连接dad dad继承sonL
		sonL->_right = dad;
		dad->_parent = sonL;
		//G为空 表明dad为根结点 
		if (Grandpa == nullptr)
		{
			//更新根结点
			_root = sonL;
			//更新根结点成员属性
			_root->_parent = nullptr;
		}
		else
		{
			//父连子
			if (Grandpa->_left == dad)
				Grandpa->_left = sonL;
			else
				Grandpa->_right = sonL;
			//子继承父
			sonL->_parent = Grandpa;
		}
		//更新_bf
		sonL->_bf = dad->_bf = 0;
	}

3.2右右型-左单旋

在这里插入图片描述

void RotateLeft(Node* dad)
{
	Node* Grandpa = dad->_parent;
	Node* sonR = dad->_right;
	Node* sonRL = sonR->_left;

	//dad连接sonRL sonRL不空继承dad 为空不继承
	dad->_right = sonRL;
	if (sonRL)
		sonRL->_parent = dad;
	//sonR连接dad dad继承sonR
	sonR->_left = dad;
	dad->_parent = sonR;
	//Grandpa为空--dad为根节点 更新后 sonR为根节点 根节点的_parent置空
	if (Grandpa == nullptr)
	{
		_root = sonR;
		_root->_parent = nullptr;
	}
	//不为空 依实际连接
	else
	{
		//父连子
		if (Grandpa->_left == dad)
			Grandpa->_left = sonR;
		else
			Grandpa->_right = sonR;
		//子继承父
		sonR->_parent = Grandpa;
	}
	//左旋目的达到 更新_bf
	dad->_bf = sonR->_bf = 0;
}

3.3左右型-左右旋

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

void RotateLR(Node* dad)
{
	Node* sonL = dad->_left;
	Node* sonLR = sonL->_right;
	int bf = sonLR->_bf;

	RotateLeft(sonL);
	RotateRight(dad);

	if (bf == 1)
	{
		sonLR->_bf = 0;
		sonL->_bf = -1;
		dad->_bf = 0;
	}
	else if (bf == -1)
	{
		sonLR->_bf = 0;
		sonL->_bf = 0;
		dad->_bf = 1;
	}
	else if (bf == 0)
	{
		sonLR->_bf = 0;
		sonL->_bf = 0;
		dad->_bf = 0;
	}
	else
	{
		assert(false);
	}
}

3.4右左型:右左旋

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

void RotateRL(Node* dad)
{
	Node* sonR = dad->_right;
	Node* sonRL = sonR->_left;
	int bf = sonRL->_bf;//最终根结点的_bf

	RotateLeft(dad->_right);
	RotateRight(dad);

	if (bf == 1)
	{
		sonRL->_bf = 0;
		dad->_bf = -1;
		sonR->_bf = 0;
	}
	else if (bf == -1)
	{
		sonRL->_bf = 0;
		dad->_bf = 0;
		sonR->_bf = 1;
	}
	else if (bf == 0)
	{
		sonRL->_bf = 0;
		dad->_bf = 0;
		sonR->_bf = 0;1
	}
	else
	{
		assert(false);
	}
}

3.5总图

在这里插入图片描述

3.完整代码

3.1AVLTree.h

#pragma once
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <array>
#include <time.h>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#include <functional>
#include <assert.h>
#include <math.h>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	pair<K, V> _pair;
	int _bf;           // balance factor

	AVLTreeNode(const pair<K, V>& pair)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _pair(pair)
		, _bf(0)
	{

	}
};

//高度平衡搜索树
template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:

	//插入--创建二叉树
	bool Insert(const pair<K, V>& pair)
	{
		//空树--new结点
		if (_root == nullptr)
		{
			_root = new Node(pair);
			return true;
		}

		//非空--插入
		//1.定位到合适位置
		Node* parent = nullptr;
		Node* cp = _root;
		while (cp)
		{
			if (pair.first > cp->_pair.first)
			{
				parent = cp;
				cp = cp->_right;
			}
			else if (pair.first < cp->_pair.first)
			{
				parent = cp;
				cp = cp->_left;
			}
			else
			{
				//搜索树不可有数据重复 -- 插入失败
				return false;
			}
		}

		//2.链接
		cp = new Node(pair);
		if (pair.first < parent->_pair.first)
		{
			parent->_left = cp;
		}
		else
		{
			parent->_right = cp;
		}
		//cp继承parent
		cp->_parent = parent;

		//构建AVL树
		while (parent)
		{
			//一、更新平衡因子

			//插入结点在右子树
			if (cp == parent->_right)
			{
				parent->_bf++;
			}
			//插入结点在左子树
			else
			{
				parent->_bf--;
			}

			//二、分类讨论

			// _bf == 1/-1 原为0 现高度受到影响
			// 回溯直至遇到根源结点 即_bf==2/-2的结点
			if (parent->_bf == 1 || parent->_bf == -1)
			{
				parent = parent->_parent;
				cp = cp->_parent;
			}
			//_bf == 0 不做处理 原为-1/1 现已满足 不继续更新
			else if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//旋转处理目的:
				//1.使得当前子树平衡 2.降低当前子树的高度

				//左单旋
				if (parent->_bf == 2 && cp->_bf == 1)
				{
					RotateL(parent);
				}
				//右单旋
				else if (parent->_bf == -2 && cp->_bf == -1)
				{
					RotateR(parent);
				}
				//左右旋
				else if (parent->_bf == -2 && cp->_bf == 1)
				{
					RotateLR(parent);
				}
				//右左旋
				else if (parent->_bf == 2 && cp->_bf == -1)
				{
					RotateRL(parent);
				}
				else
				{
					assert(false);
				}

				break;
			}
			else
			{
				assert(false);
			}
		}

		return true;
	}

	//中序遍历
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	//高度接口
	int Height()
	{
		return _Height(_root);
	}

	//判断是否满足AVL树平衡
	bool IsBalance()
	{
		return _IsBalance(_root);
	}

private:

	// 中序遍历
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_InOrder(root->_left);
		cout << root->_pair.first << " ";
		_InOrder(root->_right);
	}

	//高度接口
	int _Height(Node* root)
	{
		if (root == NULL)
			return 0;

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		return leftH > rightH ? leftH + 1 : rightH + 1;
	}

	//判断是否满足AVL树平衡
	bool _IsBalance(Node* root)
	{
		if (root == NULL)
		{
			return true;
		}

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		if (rightH - leftH != root->_bf)
		{
			cout << root->_pair.first << "Abnormal node balance factor!" << endl;
			return false;
		}

		return abs(leftH - rightH) < 2
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}

	//左单旋
	void RotateL(Node* parent)
	{
		//记录Grandpa
		Node* Grandpa = parent->_parent;

		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		//parent链接subRL subRL不空继承parent 空没必要继承
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		//subR连接parent parent继承subR
		subR->_left = parent;
		parent->_parent = subR;

		//Grandpa为空--parent为根节点 更新后 subR为根节点 根节点的_parent置空
		if (Grandpa == nullptr)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		//不为空 依实际连接
		else
		{
			//父连子
			if (Grandpa->_left == parent)
			{
				Grandpa->_left = subR;
			}
			else
			{
				Grandpa->_right = subR;
			}
			//子继承父
			subR->_parent = Grandpa;
		}

		parent->_bf = subR->_bf = 0;
	}

	//右单旋
	void RotateR(Node* parent)
	{
		Node* Grandpa = parent->_parent;

		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		subL->_right = parent;
		parent->_parent = subL;

		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (Grandpa->_left == parent)
			{
				Grandpa->_left = subL;
			}
			else
			{
				Grandpa->_right = subL;
			}
			subL->_parent = Grandpa;
		}

		subL->_bf = parent->_bf = 0;
	}

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;

		RotateL(parent->_left);
		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;
		}
		else
		{
			assert(false);
		}
	}

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		RotateR(parent->_right);
		RotateL(parent);

		if (bf == 1)
		{
			subR->_bf = 0;
			parent->_bf = -1;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			subR->_bf = 1;
			parent->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == 0)
		{
			subR->_bf = 0;
			parent->_bf = 0;
			subRL->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}


private:
	Node* _root = nullptr;
};

void Test_AVLTree1()
{
	int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	int b[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	AVLTree<int, int> tree;
	for (auto e : b)
	{
		tree.Insert(make_pair(e, e));
		if (tree.IsBalance())
		{
			cout << e << "插入成功!" << endl;
		}
		else
		{
			cout << e << "插入失败!" << endl;
		}
	}

	cout << "此树中序遍历:" << endl;
	tree.InOrder();

	if (tree.IsBalance())
	{
		cout << "此树为一棵AVL树" << endl;
	}
	else
	{
		cout << "此树不为一棵AVL树!" << endl;
	}
}

void Test_AVLTree2()
{
	srand(time(0));
	const size_t N = 10;
	AVLTree<int, int> tree;
	for (size_t i = 0; i < N; ++i)
	{
		size_t x = rand() + i;
		tree.Insert(make_pair(x, x));
		if (tree.IsBalance())
		{
			cout << x << "插入成功!" << endl;
		}
		else
		{
			cout << x << "插入失败!" << endl;
		}
	}

	cout << "此树中序遍历:" << endl;
	tree.InOrder();

	if (tree.IsBalance())
	{
		cout << "此树为一棵AVL树" << endl;
	}
	else
	{
		cout << "此树不为一棵AVL树!" << endl;
	}

	cout << "此树高度为:" << tree.Height() << endl;
}

3.2Test.cpp

#define _CRT_SECURE_NO_WARNINGS 
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <array>
#include <time.h>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#include <functional>
using namespace std;
#include "AVLTree.h"

int main()
{
	Test_AVLTree1();
	return 0;
}

4.AVL树的性能

  1. AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1.保证查找时间复杂度为logN。
  2. 创建一棵AVL树成本太大:插入时要维护其绝对平衡,旋转的次数比较多,删除时有可能要一直旋转直到根的位置。
  3. 如果需要一种查询高效且有序的数据结构,且数据的个数为不改变,可以考虑AVL树
  4. AVL树不适合需要经常修改结构的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿猿收手吧!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值