大家都愿意盲从,好像世界上最安全的事就是让自己消失在多数之中。

前言
这是我自己学习C++的第十五篇博客总结。后期我会继续把C++学习笔记开源至博客上。
上一期笔记是关于C++的set和map知识,没看的同学可以过去看看:
【C++】map与set-CSDN博客
https://blog.csdn.net/hsy1603914691/article/details/147123187
AVL树的概念
- AVL树 是一种 自平衡二叉搜索树,具有以下性质:
- 空树性质:一棵AVL树可以是空树。
- 递归性质:如果非空,则AVL树满足以下条件:
- 左右子树均为AVL树。
- 左右子树的高度差(即平衡因子)的绝对值不超过1。
AVL树 需要引入一个平衡因子的概念,每个结点都有一个平衡因子 ,任何结点的平衡因子等于右子树的高度减去左子树的高度 ,也就是说任何结点的平衡因子等于0、1 、-1。
AVL树整体结点数量和分布与完全二叉树类似,高度可以控制在log(N),那么增删查改的效率也可以控制在log(N),相比二叉搜索树有了本质的提升。

AVL树的插入
整体的插入规则
- 先按 二叉搜索树规则 进行插入。
- 新增结点只会影响祖先结点的高度 ,也就是可能会影响部分祖先结点的平衡因子。所以 需要更新从新增结点到根结点路径上的平衡因子 ,实际中最坏情况下要更新到根,有些情况更新到中间就可以停止了。
- 更新平衡因子过程中没有出现问题,则插入结束。
- 更新平衡因子过程中出现不平衡 , 对不平衡子树旋转 。旋转后,本质调平衡的同时,本质降低了子树的高度,不会再影响上一层,所以插入结束。
平衡因子更新原则
- 平衡因子 = 右子树高度 - 左子树高度 。
- 只有 子树高度变化 才会影响当前结点的平衡因子。
- 插入结点 , 会增加高度 。当新增结点在 parent的右子树 , parent的平衡因子++ ;当新增结点在 parent的左子树 , parent平衡因子-- 。
cpp
bool insert(const K& x, const V& y)
{
Node* cur = _root;
Node* parent = nullptr;
if (_root == nullptr)
{
_root = new Node(x, y);
return true;
}
else
{
while (cur != nullptr)
{
if (cur->_key < x)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > x)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;//不允许有重复
}
}
}
cur = new Node(x, y);
if (parent->_key < cur->_key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//更新平衡因子
while (parent)
{
if (cur == parent->left)
{
parent->bf--;
}
else if (cur == parent->right)
{
parent->bf++;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//需要进行旋转调整
...
}
else
{
assert(false);
}
}
return true;
}
旋转原则
- 保持二叉搜索树性质的前提下,让旋转的树从不平衡变平衡。
- 旋转总共分为四种, 左单旋 、 右单旋 、 左右双旋 、 右左双旋 。
右单旋

cpp
void Rotate_Right(Node* parent)
{
Node* ppNode = parent->_parent;
Node* sub_left = parent->_left;
Node* subl_right = sub_left->_right;
sub_left->_right=parent;
parent->_parent = sub_left;
parent->_left = subl_right;
if (subl_right)
{
subl_right->_parent = parent;
}
if (ppNode==nullptr)
{
_root = sub_left;
sub_left->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = sub_left;
}
else
{
ppNode->_right = sub_left;
}
}
}
左单旋

cpp
void Rotate_Left(Node* parent)
{
Node* ppNode = parent->_parent;
Node* sub_right = parent->_right;
Node* subr_left = sub_right->_left;
sub_right->_left = parent;
parent->_parent = sub_right;
parent->_right = subr_left;
if (subr_left)
{
subr_left->_parent = parent;
}
if (ppNode == nullptr)
{
_root = sub_right;
sub_right->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = sub_right;
}
else
{
ppNode->_right = sub_right;
}
}
}
左右双旋

cpp
void Rotate_Left_Right(Node* parent)
{
Node* sub_left = parent->_left;
Node* subl_right = sub_left->_right;
int bf=subl_right->_bf;
Rotate_Left(sub_left);
Rotate_Right(parent);
if (bf == 0)
{
parent->_bf = 0;
sub_left->_bf = 0;
subl_right->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
sub_left->_bf = -1;
subl_right->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
sub_left->_bf = 0;
subl_right->_bf = 0;
}
else
{
assert(false);
}
}
右左双旋

cpp
void Rotate_Right_Left(Node* parent)
{
Node* sub_right = parent->_right;
Node* subr_left = sub_right->_left;
int bf = subr_left->_bf;
Rotate_Right(sub_right);
Rotate_Left(parent);
if (bf == 0)
{
parent->_bf = 0;
sub_right->_bf = 0;
subr_left->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
sub_right->_bf = 0;
subr_left->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
sub_right->_bf = 1;
subr_left->_bf = 0;
}
else
{
assert(false);
}
}
插入的整体代码
cpp
bool insert(const K& x, const V& y)
{
Node* cur = _root;
Node* parent = nullptr;
if (_root == nullptr)
{
_root = new Node(x, y);
return true;
}
else
{
while (cur != nullptr)
{
if (cur->_key < x)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > x)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;//不允许有重复
}
}
}
cur = new Node(x, y);
if (parent->_key < cur->_key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//更新平衡因子
while (parent)
{
if (cur == parent->_left)
{
parent->_bf--;
}
else if (cur == parent->_right)
{
parent->_bf++;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//开始旋转
if (parent->_bf == -2 && parent->_left->_bf == -1)
{
Rotate_Right(parent);
break;
}
else if (parent->_bf == 2 && parent->_right->_bf == 1)
{
Rotate_Left(parent);
break;
}
else if (parent->_bf == -2 && parent->_left->_bf == 1)
{
Rotate_Left_Right(parent);
break;
}
else if (parent->_bf == 2 && parent->_right->_bf == -1)
{
Rotate_Right_Left(parent);
break;
}
else
{
assert(false);
}
}
else
{
assert(false);
}
}
return true;
}
void Rotate_Right(Node* parent)
{
Node* ppNode = parent->_parent;
Node* sub_left = parent->_left;
Node* subl_right = sub_left->_right;
sub_left->_right=parent;
parent->_parent = sub_left;
parent->_left = subl_right;
if (subl_right)
{
subl_right->_parent = parent;
}
if (ppNode==nullptr)
{
_root = sub_left;
sub_left->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = sub_left;
}
else
{
ppNode->_right = sub_left;
}
}
}
void Rotate_Left(Node* parent)
{
Node* ppNode = parent->_parent;
Node* sub_right = parent->_right;
Node* subr_left = sub_right->_left;
sub_right->_left = parent;
parent->_parent = sub_right;
parent->_right = subr_left;
if (subr_left)
{
subr_left->_parent = parent;
}
if (ppNode == nullptr)
{
_root = sub_right;
sub_right->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = sub_right;
}
else
{
ppNode->_right = sub_right;
}
}
}
void Rotate_Left_Right(Node* parent)
{
Node* sub_left = parent->_left;
Node* subl_right = sub_left->_right;
int bf=subl_right->_bf;
Rotate_Left(sub_left);
Rotate_Right(parent);
if (bf == 0)
{
parent->_bf = 0;
sub_left->_bf = 0;
subl_right->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
sub_left->_bf = -1;
subl_right->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
sub_left->_bf = 0;
subl_right->_bf = 0;
}
else
{
assert(false);
}
}
void Rotate_Right_Left(Node* parent)
{
Node* sub_right = parent->_right;
Node* subr_left = sub_right->_left;
int bf = subr_left->_bf;
Rotate_Right(sub_right);
Rotate_Left(parent);
if (bf == 0)
{
parent->_bf = 0;
sub_right->_bf = 0;
subr_left->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
sub_right->_bf = 0;
subr_left->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
sub_right->_bf = 1;
subr_left->_bf = 0;
}
else
{
assert(false);
}
}
AVL树的遍历
cpp
public:
void InOrder()
{
_InOrder(_root);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
else
{
_InOrder(root->_left);
cout << root->_key << " " << root->_val << endl;
_InOrder(root->_right);
}
}
AVL树的检验
cpp
public:
bool IsAVLTree(Node* root)
{
if (root == nullptr)
{
return true;
}
int left_height = _Height(root->_left);
int right_height = _Height(root->_right);
int diff = right_height - left_height;
if (abs(diff) >= 2)
{
cout << "高度差异常" << " " << root->_key;
return false;
}
if (diff != root->_bf)
{
cout << "平衡因子异常" << " " << root->_key;
return false;
}
return IsAVLTree(root->_left) && IsAVLTree(root->_right);//从中间节点向左右两边递归
}
private:
int _Height(Node* root)
{
if (root == nullptr)
{
return 0;
}
int left_Height = _Height(root->_left);
int right_Height = _Height(root->_right);
return left_Height > right_Height ? left_Height + 1 : right_Height + 1;
}
AVL树整体代码
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cassert>
using namespace std;
template <class K,class V>
struct AVLTNode
{
typedef AVLTNode<K, V> Node;
K _key;
V _val;
Node* _left;
Node* _right;
Node* _parent;
int _bf;
AVLTNode(const K& key,const V& val)
: _key(key)
, _val(val)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
template<class K, class V>
class AVLTree
{
typedef AVLTNode<K, V> Node;
typedef AVLTree<K, V> Tree;
public:
AVLTree()
:_root(nullptr)
{}
bool insert(const K& x, const V& y)
{
Node* cur = _root;
Node* parent = nullptr;
if (_root == nullptr)
{
_root = new Node(x,y);
return true;
}
else
{
while (cur != nullptr)
{
if (cur->_key < x)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > x)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;//不允许有重复
}
}
}
cur = new Node(x, y);
if (parent->_key < cur->_key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//更新平衡因子
while (parent)
{
if (cur == parent->_left)
{
parent->_bf--;
}
else if (cur == parent->_right)
{
parent->_bf++;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//开始旋转
if (parent->_bf == -2 && parent->_left->_bf == -1)
{
Rotate_Right(parent);
break;
}
else if (parent->_bf == 2 && parent->_right->_bf == 1)
{
Rotate_Left(parent);
break;
}
else if (parent->_bf == -2 && parent->_left->_bf == 1)
{
Rotate_Left_Right(parent);
break;
}
else if (parent->_bf == 2 && parent->_right->_bf == -1)
{
Rotate_Right_Left(parent);
break;
}
else
{
assert(false);
}
}
else
{
assert(false);
}
}
return true;
}
Node* Find(const K& x)
{
Node* cur = _root;
while (cur != nullptr)
{
if (cur->_key < x)
{
cur = cur->_right;
}
else if (cur->_key > x)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
void InOrder()
{
_InOrder(_root);
}
bool IsAVLTree(Node* root)
{
if (root == nullptr)
{
return true;
}
int left_height = _Height(root->_left);
int right_height = _Height(root->_right);
int diff = right_height - left_height;
if (abs(diff) >= 2)
{
cout << "高度差异常" << " " << root->_key;
return false;
}
if (diff != root->_bf)
{
cout << "平衡因子异常" << " " << root->_key;
return false;
}
return IsAVLTree(root->_left) && IsAVLTree(root->_right);//从中间节点向左右两边递归
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
else
{
_InOrder(root->_left);
cout << root->_key << " " << root->_val << endl;
_InOrder(root->_right);
}
}
void Rotate_Right(Node* parent)
{
Node* ppNode = parent->_parent;
Node* sub_left = parent->_left;
Node* subl_right = sub_left->_right;
sub_left->_right = parent;
parent->_parent = sub_left;
parent->_left = subl_right;
if (subl_right)
{
subl_right->_parent = parent;
}
if (ppNode == nullptr)
{
_root = sub_left;
sub_left->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = sub_left;
}
else
{
ppNode->_right = sub_left;
}
}
}
void Rotate_Left(Node* parent)
{
Node* ppNode = parent->_parent;
Node* sub_right = parent->_right;
Node* subr_left = sub_right->_left;
sub_right->_left = parent;
parent->_parent = sub_right;
parent->_right = subr_left;
if (subr_left)
{
subr_left->_parent = parent;
}
if (ppNode == nullptr)
{
_root = sub_right;
sub_right->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = sub_right;
}
else
{
ppNode->_right = sub_right;
}
}
}
void Rotate_Left_Right(Node* parent)
{
Node* sub_left = parent->_left;
Node* subl_right = sub_left->_right;
int bf = subl_right->_bf;
Rotate_Left(sub_left);
Rotate_Right(parent);
if (bf == 0)
{
parent->_bf = 0;
sub_left->_bf = 0;
subl_right->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
sub_left->_bf = -1;
subl_right->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
sub_left->_bf = 0;
subl_right->_bf = 0;
}
else
{
assert(false);
}
}
void Rotate_Right_Left(Node* parent)
{
Node* sub_right = parent->_right;
Node* subr_left = sub_right->_left;
int bf = subr_left->_bf;
Rotate_Right(sub_right);
Rotate_Left(parent);
if (bf == 0)
{
parent->_bf = 0;
sub_right->_bf = 0;
subr_left->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
sub_right->_bf = 0;
subr_left->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
sub_right->_bf = 1;
subr_left->_bf = 0;
}
else
{
assert(false);
}
}
int _Height(Node* root)
{
if (root == nullptr)
{
return 0;
}
int left_Height = _Height(root->_left);
int right_Height = _Height(root->_right);
return left_Height > right_Height ? left_Height + 1 : right_Height + 1;//子树的高度等于左右子树高度的最大值加1。
}
Node* _root;
};
int main()
{
AVLTree<int, string> a1;
a1.insert(1, "苹果");
a1.insert(2, "西瓜");
a1.insert(3, "菠萝");
a1.insert(8, "车厘子");
a1.insert(4, "樱桃");
a1.insert(5, "梨子");
a1.insert(6, "香蕉");
a1.insert(7, "哈密瓜");
a1.InOrder();
auto it = a1.Find(5);
if (a1.Find(5))
{
cout << it->_key << "->" << it->_val;
}
return 0;
}
致谢
感谢您花时间阅读这篇文章!如果您对本文有任何疑问、建议或是想要分享您的看法,请不要犹豫,在评论区留下您的宝贵意见。每一次互动都是我前进的动力,您的支持是我最大的鼓励。期待与您的交流,让我们共同成长,探索技术世界的无限可能!