当前位置:网站首页>AVL树的理解和实现
AVL树的理解和实现
2022-07-01 08:34:00 【GracefulBlack】
AVL树,也叫高度平衡二叉搜索树
左右子树都是AVL树
左右子树高度差(简称平衡因子)的绝对值不超过1(-1/0/1)
平衡因子 = 右子树高度 - 左子树高度
AVL树不一定需要平衡因子
使用平衡因子是一种控制实现方式
三叉链存储,有一对pair和平衡因子
插入
有一个parent,有一个cur
插入的是三叉链,parent也要指
怎么知道平衡不平衡
新插入的 平衡因子一定是0
插入在父节点的右边,父节点的平衡因子+1;插入在左边,父节点平衡因子-1
cur是新增结点,它只会影响cur节点的平衡因子
控制平衡
1.更新平衡因子 – 新增节点到根节点的祖先路径
①cur ==parent->left , parent->left–
②cur ==parent->right,parent->right++
③更新以后,parent->bf == 0,更新结束 —— 说明更新前parent -> bf是1或者-1,现在变成0,说明填上了矮的那边,parent所在子树高度不变
④更新以后,parent->bf == 1 或 -1,继续网上处理 —— 说明更新前parent->bf是0,现在变成1或-1,有一边子树变高了,parent所在子树高度
变了,会继续对上面子树有影响
往上走的过程是三叉链的威力之处
⑤更新以后,parent->bf == 2或-2, parents所在的子树就已经不平衡了,需要旋转处理
最坏的情况,一路更新到根
写的时候添加注意,方便以后查看
不是以上的五种情况直接断言,说明插入之前就有问题了
2.出现异常的平衡因子,旋转处理
简单感受
插入123 213 321
树的结构都是不同的
右单旋
抽象图,代表很多种情况
抽线图 对应的是 具象图
如果a变成h+1,会引发60的bf变成-2,触发旋转
为什么叫右单旋?因为树的左边高,需要往右边去旋转,使得左右平衡
做到两点:
①保持搜索树规则
②控制平衡
对抽象图来说,b变成60的左边,60变成30的右边
旋转的意义:1 .这棵树平衡了 2 .整体高度降了1
条件:cur的bf是-1 , parent的bf是-2 ,进行旋转
不是简单的将cur的右边(subLR)给给parent的左边这么简单的
因为不只更新平衡因子,还需要更新三叉链
b有可能是空,要避免空指针的问题
最后如果parent不是根结点,还需要把parent跟上面的结点进行链接
时时刻刻要维护好我们的三叉链
降序插入则会一直右单旋,可以调试查看
左单旋
右边高,进行左单旋
和右单旋类似
左右双旋
30轴点是右边高,90轴点是左边高
如果用单旋的方式,结果还有有错误,本来左边高,会变成右边高
左右双旋->30的结点左单旋【右边高】,90的结点右单旋【左边高】(经过左单旋,变成完全左边高,再右单旋,平衡)
步骤:
1 .30为轴点,进行左单旋
2 .90为轴点,进行右单旋
AVL树的三个大规则
1.按搜索树的规则插入
2.更新平衡因子
3.出现不平衡,旋转处理
旋转分为四种
1.左边高,要往右边压,叫做右单旋
2.右边高,要往左边压,叫做左单旋
3.通过单旋无法平衡,用双旋
判断avl树是不是平衡树?
检查平衡因子是不对的,可能会存在问题(万一平衡因子更新错了)
用高度来判断是最好的,递归检查,每一棵子树都要检查一遍
检查左右树差值是否小于2即可
这样做完以后树的形态是对的,单平衡因子不一定对(可能会引发不该旋转的时候旋转)
所以还要对平衡因子进行检查
调试是一种手段,多的是日志
双选不可以简简单单的进行左旋+右旋
期间平衡因子有多种变化,不是直接复用之前的代码可以解决的,还需要重新处理
右左双旋(图)
可以看成60的结点分发给了两边
左右双旋(图)
AVL在实际用途并不多,主要是有了红黑树
AVL树的实现代码:
AVL.h
#pragma once
#include <set>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <queue>
#include <functional>
#include <assert.h>
using namespace std;
template<class K,class V>
struct AVLNode {
//存储三叉链以及平衡因子,还有一对键值对
struct AVLNode<K, V>* _parent;
struct AVLNode<K, V>* _left;
struct AVLNode<K, V>* _right;
int _bf;
pair<K, V> _kv;
AVLNode(const pair<K,V>& kv)
:_parent(nullptr),
_left(nullptr),
_right(nullptr),
_bf(0),
_kv(kv)
{
}
};
template<class K,class V>
class AVLTree {
typedef AVLNode<K, V> Node;
public:
AVLTree()
:_root(nullptr)
{
}
//插入
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
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;
}
}
cur = new Node(kv);
if (kv.first > parent->_kv.first)
{
cur->_parent = parent;
parent->_right = cur;
}
else
{
cur->_parent = parent;
parent->_left = cur;
}
//开始调整平衡因子
while (parent)
{
if (cur == parent->_left)
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0)
{
return true;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
//如果平衡因子是1或-1的话,继续网上更新
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//如果平衡因子是2的话,就要进行旋转
//具体旋转根据树的形态来定
if (cur->_bf == 1 && parent->_bf == 2)//右树(右边高)的情况,进行左旋
{
RotateL(parent);
}
else if (cur->_bf == -1 && parent->_bf == -2)
{
RotateR(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
RotateLR(parent);
}
else if(parent->_bf == 2 && cur->_bf == -1)
{
RotateRL(parent);
}
else
{
assert(false);//不可能情况断言报错,
}
break;
}
}
return true;
}
//右旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if(subLR)
subLR->_parent = parent;
Node* parentParent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
parentParent->_left = subL;
else
parentParent->_right = subL;
subL->_parent = parentParent;
}
subL->_bf = parent->_bf = 0;
}
//左旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
//解决非空指针的问题
if (subRL)
subRL->_parent = parent;
Node* parentParent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
parentParent->_left = subR;
else
parentParent->_right = subR;
subR->_parent = parentParent;
}
subR->_bf = 0;
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;
subL->_bf = -1;
subLR = 0;
}
else if (bf == -1)
{
parent->_bf = -1;
subL->_bf = 0;
subLR = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subL->_bf = 0;
subLR = 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)
{
subRL->_bf = 0;
parent->_bf = -1;
subR->_bf = 0;
}
else if (bf == -1)
{
subRL->_bf = 0;
parent->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
subRL->_bf = 0;
parent->_bf = 0;
subR->_bf = 0;
}
else
{
assert(false);
}
}
void InOrder()
{
_InOrder(_root);
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
bool IsBalance()
{
return _IsBalance(_root);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = Height(root->_left);
int rightHeight = Height(root->_right);
return leftHeight + 1 ?rightHeight + 1 : leftHeight > rightHeight;
}
bool _IsBalance(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->_bf << endl;
cout << root->_kv.first << "的平衡因子应该是" << rightHeight - leftHeight << endl;
return false;
}
return abs(rightHeight - leftHeight)< 2
&& _IsBalance(root->_left)
&& _IsBalance(root->_right);
}
private:
Node* _root;
};
void TestAVLTree()
{
AVLTree<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(make_pair(e, e));
cout << "Insert" << e << ":" << t.IsBalance() << endl;
}
t.InOrder();
}
边栏推荐
- 5mo3 UHI HII HII 17mn4 19Mn6 executive standard
- Burpsuite -- brute force cracking of intruder
- Intelligent constant pressure irrigation system
- Leetcode t31: prochain arrangement
- 分享2022上半年我读过的7本书
- 【无标题】
- 【js逆向】md5加密参数破解
- Yolov5 advanced 7 target tracking latest environment setup
- 你了解数据是如何存储的吗?(C整型和浮点型两类)
- 《微机原理》-绪论
猜你喜欢
What is 1cr0.5mo (H) material? 1cr0.5mo (H) tensile yield strength
There are many problems in sewage treatment, and the automatic control system of pump station is solved in this way
Matlab [functions and images]
Li Kou 1358 -- number of substrings containing all three characters (double pointer)
【无标题】
Screenshot tips
Thread safety analysis of [concurrent programming JUC] variables
【MFC开发(17)】高级列表控件List Control
Centos7 shell脚本一键安装jdk、mongo、kafka、ftp、postgresql、postgis、pgrouting
《微机原理》-绪论
随机推荐
【MFC开发(16)】树形控件Tree Control
Configuration and startup of Chang'an chain synchronization node
MATLAB【函数和图像】
避免按钮重复点击的小工具bimianchongfu.queren()
Yolov5进阶之六目标追踪环境搭建
嵌入式工程师常见面试题2-MCU_STM32
The era of low threshold programmers is gone forever behind the sharp increase in the number of school recruitment for Internet companies
factory type_id::create过程解析
Foundation: 2 The essence of image
华为机试真题专栏订阅指引
Serial port to WiFi module communication
yolov5训练可视化指标的含义
你了解数据是如何存储的吗?(C整型和浮点型两类)
Agrometeorological environment monitoring system
如何招到适合自己店铺的淘宝主播
截图小妙招
C语言指针的进阶(下)
性能提升2-3倍!百度智能云第二代昆仑芯服务器上线
FreeRTOS学习简易笔记
Pipeline detection of UAV Based on gazebo