作为搜索结构,二叉搜索树有其高效的搜索效率,但是同时也有着其本质的缺陷,就是在数据呈现顺序的时候,效率低下,因此不适合大多数的数据存储,但是如果将其修改,成为一个平衡树,结合两者特点,就可以完成高效的查找,因此我们学习平衡搜索二叉树~AVL树
AVL树的特点是,左子树和右子树的高度差不超过一,也就是说,左右子树的高度最多差一,并且要保证所有的子树都满足这个条件,因此分部均匀,且具有相对优秀的效率。
插入和删除都是二叉搜索树的方式,但是在这之后,需要进行平衡的旋转工作,因此我们一般是随着节点往上走来调节平衡,所以结构一般使用三叉链的结构,来寻找上一个节点,或者可以使用栈保留顺序,来进行反向寻找,两种方式都可以,下面我们使用第一种方式来写代码。
首先我们要明白,AVL树是如何保持平衡的,是利用一个叫平衡因子的数据,平衡因子是右子树高度减去左子树高度,用平衡因子来衡量需不需要旋转,以及一些信息。
插入:我们明白插入一定只能影响一条路径上的高度,首先要明白,左节点插入,balance factor 一定是减一的,而右边是加一的。
那么分为三种情况
如果说更新后,bf为0那么一定是将矮的那边补齐,因此高度不变对上层不影响。
如果更新后,bf为-1或1,那么一定是相等的高度增加了,因此对上层有影响,向上调整。
如果更新后bf为2或-2,那么已经不平衡了,因此进行旋转。
旋转分成四种情况,左单旋,右单旋,左右双旋,右左双旋。
删除的话则和插入相反,右边删除,bf–,左边删除,bf++,删除后,如果bf为0,则说明高度变了,因为高度是长的那个,因此,如果变成1或者-1,说明本来是相等的,删了一个高度是不变的。
删除的情况是比较复杂,大方向分为2和-2两种情况,它们是一样的,只是旋转的方向不一样,因为删除的话,一定是兄弟节点变高了,所以我们首先要寻找兄弟节点的bf为多少,进行讨论
bf为2:
假设兄弟节点b 的bf为0,则直接左单旋,就直接平衡。
假设兄弟节点的b 的bf为1,则左单旋,但是向上迁移,因为高度总体低了1
前两种的旋转过后,bf都是0
如果是兄弟节点的bf为-1,则进行双旋,一定是它的subL,左子树高,那么对左子树的bf进行讨论,双旋后有三种不同的bf调节方式。
第一种subL的bf为0,旋转后,b和p的节点bf都为0
第二种subL的bf为1,旋转后,p的bf为-1,b为0
第三种subL的bf为-1,旋转后,p的bf为0,b为1
然后向上迁移,总体高度减一。
bf为-2的情况与之一样,只是旋转方向变化。
#pragma once
#include <iostream>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf;//平衡因子
pair<K, V> _kv;
AVLTreeNode(const pair<K,V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
,_kv(kv)
{}
};
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* 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 (parent->_kv.first > kv.first)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
while (parent)
{
if (cur == parent->_left)
parent->_bf--;
else
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)
{
if (cur->_bf == 1)
{
RotateL(parent);
}
else
{
RotateRL(parent);
}
}
else
{
if (cur->_bf == -1)
{
RotateR(parent);
}
else
{
RotateLR(parent);
}
}
break;
}
}
}
bool erase(const pair<K, V>& kv)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = nullptr;
int ex = 1;
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
{
ex = 0;
if (cur->_left == nullptr)
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
Node* del = cur;
cur = cur->_right;
delete del;
break;
}
else if (cur->_right == nullptr)
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
Node* del = cur;
cur = cur->_left;
delete del;
break;
}
else
{
Node* rightMinParent = cur;
Node* rightMin = cur->_right;
while (rightMin->_left)
{
rightMinParent = rightMin;
rightMin = rightMin->_left;
}
cur->_kv = rightMin->_kv;
if (rightMin == rightMinParent->_left)
{
rightMinParent->_left = rightMin->_right;
}
else
{
rightMinParent->_right = rightMin->_right;
}
parent = rightMinParent;
cur = rightMin->_right;
delete rightMin;
break;
}
}
}
if (ex)
{
return false;
}
while (parent)
{
if (cur = parent->_left)
parent->_bf++;
else
parent->_bf--;
if (parent->_bf == 0)
{
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
break;
}
else
{
if (parent->_bf == 2)
{
Node* Brother = parent->_right;
if (Brother->_bf == 0)
{
RotateL(parent);
parent->_bf = 1;
Brother->_bf = -1;
break;
}
else if (Brother->_bf == 1)
{
RotateL(parent);
parent->_bf = Brother->_bf = 0;
cur = Brother;
parent = cur->_parent;
}
else
{
Node* subL = Brother->_left;
int bf = subL->_bf;
RotateR(Brother);
RotateL(parent);
if (bf == 0)
{
parent->_bf = 0;
Brother->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
Brother->_bf = 1;
}
else
{
parent->_bf = -1;
Brother->_bf = 0;
}
subL->_bf = 0;
cur = subL;
parent = subL->_parent;
}
}
else
{
Node* Brother = parent->_left;
if (Brother->_bf == 0)
{
RotateR(parent);
Brother->_bf = 1;
parent->_bf = -1;
}
else if (Brother->_bf == -1)
{
RotateR(parent);
Brother->_bf = 0;
parent->_bf = 0;
cur = Brother;
parent = cur->_parent;
}
else
{
Node* subR = Brother->_right;
int bf = subR->_bf;
RotateL(Brother);
RotateR(parent);
if (bf == 0)
{
parent->_bf == 0;
Brother->_bf == 0;
}
else if (bf == 1)
{
parent->_bf = 0;
Brother->_bf = -1;
}
else
{
parent->_bf = 1;
Brother->_bf = 0;
}
subR->_bf = 0;
cur = subR;
parent = cur->_parent;
}
}
}
}
return true;
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
if (subRL)
subRL->_parent = parent;
parent->_right = subRL;
Node* ppnode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_left = parent;
subR->_parent = nullptr;
}
else
{
subR->_parent = ppnode;
subR->_left = parent;
if (parent == ppnode->_left)
ppnode->_left = subR;
else
ppnode->_right = subR;
}
parent->_bf = subR->_bf = 0;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
if(subLR)
subLR->_parent = parent;
parent->_left = subLR;
Node* ppnode = parent->_parent;
parent->_parent = subL;
subL->_right = parent;
if (_root = parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
ppnode->_left = subL;
else
ppnode->_right = subL;
subL->_parent = ppnode;
}
parent->_bf = subL->_bf = 0;
}
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 1)
{
subR->_bf = 0;
parent->_bf = -1;
subRL->_bf = 0;
}
else if (bf == -1)
{
subR->_bf = 1;
parent->_bf = 0;
subRL->_bf = 0;
}
else if (bf == 0)
{
subR->_bf = 0;
subR->_bf = 0;
parent->_bf = 0;
}
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
if (bf == 1)
{
parent->_bf = 0;
subL->_bf = -1;
subLR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
void InOrder()
{
_InOrder(_root);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
return max(Height(root->_left), Height(root->_right)) + 1;
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
return true;
return abs(Height(root->_left) - Height(root->_right)) < 2
&& _IsBalance(root->_left) && _IsBalance(root->_right);
}
bool IsBalance()
{
return _IsBalance(_root);
}
private:
Node* _root = nullptr;
};
void test()
{
int a[] = { 16,3,7,11,9,26,18,14,15 };
AVLTree<int, int> t;
for (auto e : a)
{
t.insert(make_pair(e, e));
}
t.InOrder();
cout << t.IsBalance() << endl;
}