当前位置:网站首页>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();
}
边栏推荐
- 《单片机原理与应用》——并行IO口原理
- Luogu p3799 demon dream stick
- Foundation: 3 Opencv getting started images and videos
- Guidelines and principles of did
- NFT监管要点和海外政策
- 公网集群对讲+GPS可视追踪|助力物流行业智能化管理调度
- In depth learning training sample amplification and tag name modification
- Introduction to 18mnmo4-5 steel plate executive standard and delivery status of 18mnmo4-5 steel plate, European standard steel plate 18mnmo4-5 fixed rolling
- 2022 ordinary scaffolder (special type of construction work) examination question bank and the latest analysis of ordinary scaffolder (special type of construction work)
- 01 numpy introduction
猜你喜欢

Gateway-88

MATLAB【函数求导】

基于Gazebo的无人机管道检测
![Matlab [function derivation]](/img/ba/9fb9da8a458d0c74b29b21a17328fc.png)
Matlab [function derivation]

15Mo3 German standard steel plate 15Mo3 chemical composition 15Mo3 mechanical property analysis of Wuyang Steel Works

Huawei machine test questions column subscription Guide

《微机原理》—总线及其形成

《单片机原理与应用》——并行IO口原理

Model and view of QT

Advanced level of C language pointer (Part 1)
随机推荐
Comprehensive experiment Li
5mo3 UHI HII HII 17mn4 19Mn6 executive standard
Intelligent constant pressure irrigation system
NFT监管要点和海外政策
【MFC开发(16)】树形控件Tree Control
[Yu Yue education] Shandong Vocational College talking about railway reference materials
1. Connection between Jetson and camera
Properties of 15MnNiNbDR low temperature vessel steel, Wugang 15MnNiDR and 15MnNiNbDR steel plates
Leetcode T34: 在排序数组中查找元素的第一个和最后一个位置
The meaning of yolov5 training visualization index
电脑小技巧
[深度剖析C语言] —— 数据在内存中的存储
Screenshot tips
Audio audiorecord create (I)
Intelligent water conservancy solution
How to recruit Taobao anchor suitable for your own store
[no title] free test questions for constructor municipal direction general foundation (constructor) and theoretical test for constructor municipal direction general foundation (constructor) in 2022
基础:3.opencv快速入门图像和视频
Introduction to R language
Huawei machine test questions column subscription Guide