当前位置:网站首页>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();
}
边栏推荐
- MAVROS发送自定义话题消息给PX4
- yolov5训练可视化指标的含义
- How to use OKR as the leadership framework of marketing department
- Centos7 shell脚本一键安装jdk、mongo、kafka、ftp、postgresql、postgis、pgrouting
- 【MFC开发(17)】高级列表控件List Control
- 2022 ordinary scaffolder (special type of construction work) examination question bank and the latest analysis of ordinary scaffolder (special type of construction work)
- 电视机尺寸与观看距离
- 2022.2.15
- 【C】 Summary of wrong questions in winter vacation
- Suivi des cibles de manoeuvre - - mise en oeuvre du modèle statistique actuel (modèle CS) filtre Kalman étendu / filtre Kalman sans trace par MATLAB
猜你喜欢

2022.2.15

Mavros sends a custom topic message to Px4

基于Gazebo的无人机管道检测

截图小妙招
![Matlab [function derivation]](/img/ba/9fb9da8a458d0c74b29b21a17328fc.png)
Matlab [function derivation]

基础:2.图像的本质
![[detailed explanation of Huawei machine test] judgment string subsequence [2022 Q1 Q2 | 200 points]](/img/0f/972cde8c749e7b53159c9d9975c9f5.png)
[detailed explanation of Huawei machine test] judgment string subsequence [2022 Q1 Q2 | 200 points]

The era of low threshold programmers is gone forever behind the sharp increase in the number of school recruitment for Internet companies

Guidelines and principles of did

明明设计的是高带宽,差点加工成开路?
随机推荐
Properties of 15MnNiNbDR low temperature vessel steel, Wugang 15MnNiDR and 15MnNiNbDR steel plates
2022 examination summary of quality controller civil engineering direction post skills (quality controller) and reexamination examination of quality controller civil engineering direction post skills
嵌入式工程师面试-常问问题集
shardingSphere
Manually dig XSS vulnerabilities
Matlab tips (23) matrix analysis -- simulated annealing
factory type_id::create过程解析
2022 ordinary scaffolder (special type of construction work) examination question bank and the latest analysis of ordinary scaffolder (special type of construction work)
MATLAB【函数和图像】
Yolov5 advanced six target tracking environment construction
基础:2.图像的本质
电脑小技巧
ARM v7的体系结构A、R、M区别,分别应用在什么领域?
[JS reverse] MD5 encryption parameter cracking
5mo3 UHI HII HII 17mn4 19Mn6 executive standard
leetcode T31:下一排列
Yolov5进阶之七目标追踪最新环境搭建
Redis publish subscription
Introduction to 18mnmo4-5 steel plate executive standard and delivery status of 18mnmo4-5 steel plate, European standard steel plate 18mnmo4-5 fixed rolling
机动目标跟踪——当前统计模型(CS模型)扩展卡尔曼滤波/无迹卡尔曼滤波 matlab实现