系列文章目录
第二篇 数据结构学习之AVL树的插入与删除
前言
AVL 树是一种高度平衡的二叉搜索树,以发明者 Adelson-Velsky 和 Landis 的名字命名。它通过在插入和删除操作后调整树的平衡,确保任意节点的左右子树高度差不超过 1。与红黑树类似,AVL 树的查找、插入和删除的时间复杂度为O(logn),但 AVL 树更加严格地平衡,因此通常在查找操作上表现更好。本文将介绍 AVL 树的特点,并通过 C++ 代码实现插入、删除、平衡和旋转操作。
一、AVL 树的基本概念
AVL 树是一种自平衡的二叉搜索树,每个节点的左右子树的高度差(即平衡因子)不超过 1。AVL 树的插入和删除操作会自动调整树的平衡性,确保查找操作的时间复杂度始终为 O(logn)。
AVL 树的主要特点:
1,每个节点的左右子树的高度差不超过 1。
2,每次插入或删除节点后,如果树不平衡,则通过旋转操作进行调整,恢复平衡。
3,AVL 树中的平衡因子定义为:
平衡因子 = 左子树高度 - 右子树高度
- 平衡因子为 1、0 或 -1 的节点被认为是平衡的。
- 平衡因子超过 1 或 -1 的节点需要进行旋转调整。
二、参考视频链接
三、代码实现
1. 定义节点类
在 C++ 中,我们首先定义一个节点类,包括颜色、值、左孩子、右孩子和父节点指针。
template<class K,class V>
struct AVLTreeNode
{
typedef AVLTreeNode<K, V> Node;
Node* _left;
Node* _right;
Node* _parent;
pair<K, V> _kv;
int _bf;//平衡因子,右树高度-左树高度
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _bf(0)
{
}
};
template<class K,class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
Node* _root = nullptr;
};
2.旋转方法
包括左旋,右旋,左右双旋,右左双旋
//左旋
Node* RotateL(Node* parent)
{
Node* Rnode = parent->_right;
Node* RLnode = Rnode->_left;
parent->_right = RLnode;
//RLnode可能为空
if (RLnode) RLnode->_parent = parent;
Rnode->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = Rnode;
if (parent == _root)
{
_root = Rnode;
}
else if (parent == ppnode->_left)
{
ppnode->_left = Rnode;
}
else
{
ppnode->_right = Rnode;
}
Rnode->_parent = ppnode;
Rnode->_bf = 0;
parent->_bf = 0;
return Rnode;
}
//右旋
Node* RotateR(Node* parent)
{
Node* Lnode = parent->_left;
Node* LRnode = Lnode->_right;
parent->_left = LRnode;
//LRnode可能为空
if (LRnode) LRnode->_parent = parent;
Lnode->_right = parent;
Node* ppnode = parent->_parent;
parent->_parent = Lnode;
if (parent == _root)
{
_root = Lnode;
}
else if (parent == ppnode->_left)
{
ppnode->_left = Lnode;
}
else
{
ppnode->_right = Lnode;
}
Lnode->_parent = ppnode;
parent->_bf = 0;
Lnode->_bf = 0;
return Lnode;
}
//左右双旋
Node* RotateLR(Node* parent)
{
Node* Lnode = parent->_left;
Node* LRnode = Lnode->_right;
int bf = LRnode->_bf;
RotateL(Lnode);
RotateR(parent);
LRnode->_bf = 0;
if (bf == 1)
{
parent->_bf = 0;
Lnode->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
Lnode->_bf = 0;
}
//该节点就是新增结点
else if (bf == 0)
{
parent->_bf = 0;
Lnode->_bf = 0;
}
else
{
//树出现问题
assert(false);
}
return LRnode;
}
//右左双旋
Node* RotateRL(Node* parent)
{
Node* Rnode = parent->_right;
Node* RLnode = Rnode->_left;
int bf = RLnode->_bf;
RotateR(Rnode);
RotateL(parent);
RLnode->_bf = 0;
if (bf == -1)
{
Rnode->_bf = 1;
parent->_bf = 0;
}
else if (bf == 1)
{
Rnode->_bf = 0;
parent->_bf = -1;
}
//该节点就是新增结点
else if (bf == 0)
{
Rnode->_bf = 0;
parent->_bf = 0;
}
else
{
//树出现问题
assert(false);
}
return RLnode;
}
3.AVL树插入操作
在 AVL 树中插入节点后,需要检查是否打破了平衡。根据节点的平衡因子进行不同类型的旋转调整。
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* tmp = _root;
Node* parent = nullptr;
while (tmp)
{
if (tmp->_kv.first < kv.first)
{
parent = tmp;
tmp = tmp->_right;
}
else if (tmp->_kv.first > kv.first)
{
parent = tmp;
tmp = tmp->_left;
}
else
{
return false;
}
}
tmp = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = tmp;
}
else
{
parent->_left = tmp;
}
tmp->_parent = parent;
while (parent)
{
if (tmp == parent->_right)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
tmp = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//旋转调节
if (parent->_bf == 2 && tmp->_bf == 1)
{
//左单旋
RotateL(parent);
}
else if (parent->_bf == -2 && tmp->_bf == -1)
{
//右单旋
RotateR(parent);
}
else if (parent->_bf == 2 && tmp->_bf == -1)
{
//右左双旋
RotateRL(parent);
}
else if (parent->_bf == -2 && tmp->_bf == 1)
{
//左右双旋
RotateLR(parent);
}
else
{
//树出现问题
assert(false);
}
break;
}
else
{
//树已经是错误的
assert(false);
return false;
}
}
return true;
}
4.AVL树删除操作
AVL 树的删除操作和插入类似,在删除节点后需要调整树的平衡,以确保 AVL 树的平衡性。
bool Erase(const K& key)
{
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_kv.first < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
parent = cur;
cur = cur->_left;
}
else
{
Node* del = cur;
//找到了
//左子树为空
if (cur->_left == nullptr)
{
//根节点
if (cur == _root)
{
_root = cur->_right;
}
else if (parent->_left == cur)
{
parent->_bf++;
parent->_left = cur->_right;
}
else
{
parent->_bf--;
parent->_right = cur->_right;
}
if (cur->_right) cur->_right->_parent = parent;
}
//右为空
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else if (parent->_left == cur)
{
parent->_bf++;
parent->_left = cur->_left;
}
else
{
parent->_bf--;
parent->_right = cur->_left;
}
if (cur->_left) cur->_left->_parent = parent;
}
//左右都不为空
else
{
//替换法删除,替换右子树最左节点
cur = cur->_right;
parent = del;
while (cur->_left)
{
parent = cur;
cur = cur->_left;
}
del->_kv = cur->_kv;
if (parent->_left == cur)
{
parent->_bf++;
parent->_left = cur->_right;
}
else
{
parent->_bf--;
parent->_right = cur->_right;
}
if (cur->_right) cur->_right->_parent = parent;
}
del = cur;
//调节平衡因子
while (parent)//最多更新到根
{
if (parent->_bf == 1 || parent->_bf == -1)
{
break;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//右旋
if (parent->_bf == -2 && parent->_left->_bf == -1)
{
parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//左旋
else if (parent->_bf == 2 && parent->_right->_bf == 1)
{
parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//左右双旋
else if (parent->_bf == -2 && parent->_left->_bf == 1)
{
parent = RotateLR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//右左双旋
else if (parent->_bf == 2 && parent->_right->_bf == -1)
{
parent = RotateRL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//左旋
else if (parent->_bf == 2 && parent->_right->_bf == 0)
{
Node* Tparent = parent;
Node* Rnode = parent->_right;
parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
Tparent->_bf = 1;
Rnode->_bf = -1;
}
//右旋
else if (parent->_bf == -2 && parent->_left->_bf == 0)
{
Node* Tparent = parent;
Node* Lnode = parent->_left;
parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
Tparent->_bf = -1;
Lnode->_bf = 1;
}
else
{
assert(false);
}
}
if (parent->_bf == 0)
{
cur = parent;
parent = parent->_parent;
if (parent && parent->_left == cur)
{
parent->_bf++;
}
else if (parent && parent->_right == cur)
{
parent->_bf--;
}
}
}
delete del;
return true;
}
}
return false;
}
四,总体代码
#pragma once
#include <assert.h>
#include <vector>
//旋转情况
//右树右边插入,parent的_bf为2,发生左单旋
//右树左边插入,parent的_bf为2,发生右左双旋
//左树左边插入,parent的_bf为2,发生右单旋
//左树右边插入,parent的_bf为2,发生左右双旋
//旋转后仍然是搜索树,从不平衡到平衡,高度减少
template<class K,class V>
struct AVLTreeNode
{
typedef AVLTreeNode<K, V> Node;
Node* _left;
Node* _right;
Node* _parent;
pair<K, V> _kv;
int _bf;//平衡因子,右树高度-左树高度
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _bf(0)
{
}
};
template<class K,class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* tmp = _root;
Node* parent = nullptr;
while (tmp)
{
if (tmp->_kv.first < kv.first)
{
parent = tmp;
tmp = tmp->_right;
}
else if (tmp->_kv.first > kv.first)
{
parent = tmp;
tmp = tmp->_left;
}
else
{
return false;
}
}
tmp = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = tmp;
}
else
{
parent->_left = tmp;
}
tmp->_parent = parent;
while (parent)
{
if (tmp == parent->_right)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
tmp = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//旋转调节
if (parent->_bf == 2 && tmp->_bf == 1)
{
//左单旋
RotateL(parent);
}
else if (parent->_bf == -2 && tmp->_bf == -1)
{
//右单旋
RotateR(parent);
}
else if (parent->_bf == 2 && tmp->_bf == -1)
{
//右左双旋
RotateRL(parent);
}
else if (parent->_bf == -2 && tmp->_bf == 1)
{
//左右双旋
RotateLR(parent);
}
else
{
//树出现问题
assert(false);
}
break;
}
else
{
//树已经是错误的
assert(false);
return false;
}
}
return true;
}
void InOrder()
{
_InOrder(_root);
}
int Height()
{
return _Height(_root);
}
bool IsBanlance()
{
int count = 0;
return _IsBanlance(_root,count);
}
int size()
{
int num = 0;
_size(_root,num);
return num;
}
bool Erase(const K& key)
{
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_kv.first < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
parent = cur;
cur = cur->_left;
}
else
{
Node* del = cur;
//找到了
//左子树为空
if (cur->_left == nullptr)
{
//根节点
if (cur == _root)
{
_root = cur->_right;
}
else if (parent->_left == cur)
{
parent->_bf++;
parent->_left = cur->_right;
}
else
{
parent->_bf--;
parent->_right = cur->_right;
}
if (cur->_right) cur->_right->_parent = parent;
}
//右为空
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else if (parent->_left == cur)
{
parent->_bf++;
parent->_left = cur->_left;
}
else
{
parent->_bf--;
parent->_right = cur->_left;
}
if (cur->_left) cur->_left->_parent = parent;
}
//左右都不为空
else
{
//替换法删除,替换右子树最左节点
cur = cur->_right;
parent = del;
while (cur->_left)
{
parent = cur;
cur = cur->_left;
}
del->_kv = cur->_kv;
if (parent->_left == cur)
{
parent->_bf++;
parent->_left = cur->_right;
}
else
{
parent->_bf--;
parent->_right = cur->_right;
}
if (cur->_right) cur->_right->_parent = parent;
}
del = cur;
//调节平衡因子
while (parent)//最多更新到根
{
if (parent->_bf == 1 || parent->_bf == -1)
{
break;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//右旋
if (parent->_bf == -2 && parent->_left->_bf == -1)
{
parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//左旋
else if (parent->_bf == 2 && parent->_right->_bf == 1)
{
parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//左右双旋
else if (parent->_bf == -2 && parent->_left->_bf == 1)
{
parent = RotateLR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//右左双旋
else if (parent->_bf == 2 && parent->_right->_bf == -1)
{
parent = RotateRL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
}
//左旋
else if (parent->_bf == 2 && parent->_right->_bf == 0)
{
Node* Tparent = parent;
Node* Rnode = parent->_right;
parent = RotateL(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
Tparent->_bf = 1;
Rnode->_bf = -1;
}
//右旋
else if (parent->_bf == -2 && parent->_left->_bf == 0)
{
Node* Tparent = parent;
Node* Lnode = parent->_left;
parent = RotateR(parent);//旋转之后,之前的Parent会变成子,所以旋转添加一个返回值,为实际新的parent
Tparent->_bf = -1;
Lnode->_bf = 1;
}
else
{
assert(false);
}
}
if (parent->_bf == 0)
{
cur = parent;
parent = parent->_parent;
if (parent && parent->_left == cur)
{
parent->_bf++;
}
else if (parent && parent->_right == cur)
{
parent->_bf--;
}
}
}
delete del;
return true;
}
}
return false;
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
private:
void _size(const Node* root, int& num)
{
if (root == nullptr)
{
return ;
}
_size(root->_left, num);
++num;
_size(root->_right, num);
}
bool _IsBanlance(Node* root,int& count)
{
if (root == nullptr)
{
count = 0;
return true;
}
int left = 0, right = 0;
if (!_IsBanlance(root->_left,left) || !_IsBanlance(root->_right,right))
{
return false;
}
if (abs(right - left) >= 2)
{
cout << "平衡因子绝对值>=2" << endl;
return false;
}
else if (right - left != root->_bf)
{
cout << "平衡因子异常" << endl;
return false;
}
count = left > right ? left + 1 : right + 1;
return true;
}
int _Height(const Node* root)
{
if (root == nullptr)
{
return 0;
}
int left = _Height(root->_left);
int right = _Height(root->_right);
return left > right ? left + 1 : right + 1;
}
void _InOrder(const Node* node)
{
if (node == nullptr)
{
return;
}
_InOrder(node->_left);
cout << node->_kv.first << ":" << node->_kv.second << endl;
_InOrder(node->_right);
}
//左旋
Node* RotateL(Node* parent)
{
Node* Rnode = parent->_right;
Node* RLnode = Rnode->_left;
parent->_right = RLnode;
//RLnode可能为空
if (RLnode) RLnode->_parent = parent;
Rnode->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = Rnode;
if (parent == _root)
{
_root = Rnode;
}
else if (parent == ppnode->_left)
{
ppnode->_left = Rnode;
}
else
{
ppnode->_right = Rnode;
}
Rnode->_parent = ppnode;
Rnode->_bf = 0;
parent->_bf = 0;
return Rnode;
}
//右旋
Node* RotateR(Node* parent)
{
Node* Lnode = parent->_left;
Node* LRnode = Lnode->_right;
parent->_left = LRnode;
//LRnode可能为空
if (LRnode) LRnode->_parent = parent;
Lnode->_right = parent;
Node* ppnode = parent->_parent;
parent->_parent = Lnode;
if (parent == _root)
{
_root = Lnode;
}
else if (parent == ppnode->_left)
{
ppnode->_left = Lnode;
}
else
{
ppnode->_right = Lnode;
}
Lnode->_parent = ppnode;
parent->_bf = 0;
Lnode->_bf = 0;
return Lnode;
}
//左右双旋
Node* RotateLR(Node* parent)
{
Node* Lnode = parent->_left;
Node* LRnode = Lnode->_right;
int bf = LRnode->_bf;
RotateL(Lnode);
RotateR(parent);
LRnode->_bf = 0;
if (bf == 1)
{
parent->_bf = 0;
Lnode->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
Lnode->_bf = 0;
}
//该节点就是新增结点
else if (bf == 0)
{
parent->_bf = 0;
Lnode->_bf = 0;
}
else
{
//树出现问题
assert(false);
}
return LRnode;
}
//右左双旋
Node* RotateRL(Node* parent)
{
Node* Rnode = parent->_right;
Node* RLnode = Rnode->_left;
int bf = RLnode->_bf;
RotateR(Rnode);
RotateL(parent);
RLnode->_bf = 0;
if (bf == -1)
{
Rnode->_bf = 1;
parent->_bf = 0;
}
else if (bf == 1)
{
Rnode->_bf = 0;
parent->_bf = -1;
}
//该节点就是新增结点
else if (bf == 0)
{
Rnode->_bf = 0;
parent->_bf = 0;
}
else
{
//树出现问题
assert(false);
}
return RLnode;
}
private:
Node* _root = nullptr;
};
总结
这里附带一下测试代码
void test_AVLTree1()
{
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };
AVLTree<int, int> al;
for (auto e : a)
{
al.Insert(make_pair(e, e));
cout << e << "->" << al.IsBanlance() << endl;
}
al.InOrder();
cout << al.IsBanlance() << endl;
}
void test_AVLTree2()
{
const int N = 3500000;
vector<int> v;
v.reserve(N);
srand(time(0));
for (size_t i = 0; i < N; i++)
{
v.push_back((rand() + i));
}
//for (auto e : v)
//{
// cout << e << " " ;
//}
cout << endl;
size_t begin2 = clock();
AVLTree<int, int> t;
for (auto e : v)
{
t.Insert(make_pair(e, e));
}
size_t end2 = clock();
cout << t.IsBanlance() << endl;
cout << "Insert:" << end2 - begin2 << endl;
cout <<"Height:"<< t.Height() << endl;
cout << "size:"<<t.size() << endl;
size_t begin1 = clock();
int flag = 0;
for (auto e : v)
{
t.Find(e);
t.Erase(e);
/* int i = t.IsBanlance();
if (i == 0)
{
flag++;
}*/
}
cout << "flag:" << flag << endl;
for (size_t i = 0; i < N; i++)
{
t.Find((rand() + i));
}
size_t end1 = clock();
cout << "Find:" << end1 - begin1 << endl;
}
AVL 树是理论上最早提出的自平衡二叉搜索树之一,以其严格的平衡性保障了快速的数据查找操作。在查找密集的应用中,AVL 树因其优越的平衡性被广泛采用。尽管插入和删除操作在 AVL 树中较为复杂,但它依然是一种有效的数据结构选择,特别适合那些更注重查找效率的场景。

1405

被折叠的 条评论
为什么被折叠?



