AVL树又名高度平衡的搜索二叉树,上一篇文章我们讲到二叉搜索树时,说到它存在一个问题:退化,这使得它的时间复杂度从O(lgN)降到了O(N)。为了解决这个问题,出现了一棵新的树,也就是AVLtree,我们先来看看它的性质:
1,它是一棵搜索 二叉树,所以满足每个节点的值大于左子树中任意节点的值,并且小于右子树中任意节点的值。
2,它是一棵平衡树,他要求每个节点的左右子树的深度之差不能超过1,即这棵树的倒数第二层节点是满的。
3,每一棵子树都是一棵AVL树;
4,每个节点都有一个平衡因子bf,取值为-1、0、1 。它的值等于右子树的深度减去左子树的深度。
AVL树节点的结构如下:
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K,V>* _left;
AVLTreeNode<K,V>* _right;
AVLTreeNode<K,V>* _parent;
K _key;
V _value;
int _bf; //平衡因子
AVLTreeNode(const K& key,const V& value)
:_left(NULL),_right(NULL),_parent(NULL),_key(key),_value(value),_bf(0)
{}
};
对于AVL树的操作,这里主要讲解一下插入
插入操作中,通过对平衡因子的判定来进行相应的旋转操作来改变树的结构。整个过程可以分为三个过程:1,寻找插入位置;2,插入;3,调整(重点也是难点)。对此我画了个流程图,如下:
代码如下:
bool Insert(const K& key,const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
return true;
}
Node* cur = _root;
Node* parent = cur;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
return false;
}
//找到插入的位置 插入
cur = new Node(key, value);
cur->_parent = parent;
if (parent->_key > key)
parent->_left = cur;
else
parent->_right = cur;
//调整平衡因子
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 = cur->_parent;
}
else // parent->_bf == 2 / == -2
{
//旋转
if (parent->_bf == 2)
{
if (cur->_bf == 1)
{
RotateL(parent);
}
else
{
RotateRL(parent);
}
}
else
{
if (cur->_bf == 1)
{
RotateLR(parent);
}
else
{
RotateR(parent);
}
}
break;
}
}
return true;
}
下面我们再一次来看一下四种旋转(LL, LR, RR, RL):
1,对于LL,在左旋之后,只需将该节点(parent)和右孩子根节点(subR)的平衡因子置为0即可。
代码如下:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* pparent = parent->_parent;
if (pparent)
{
parent->_parent = subR;
if (pparent->_left == parent)
pparent->_left = subR;
else
pparent->_right = subR;
}
else
_root = subR;
subR->_parent = pparent;
subR->_bf = parent->_bf = 0;
}
2,对于RR,在右旋之后,只需将该节点(parent)和左孩子根节点(subL)的平衡因子置为0即可。
代码如下:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* pparent = parent->_parent;
if (pparent)
{
parent->_parent = subL;
if (pparent->_left == parent)
pparent->_left = subL;
else
pparent->_right = subL;
}
else
_root = subL;
subL->_parent = pparent;
subL->_bf = parent->_bf = 0;
}
3,对于LR,保存subLR的平衡因子,用于后面判断:如果为1,subRL的右孩子会补为parent的左孩子,subL的右节点无人补,是空,subL的bf置为-1,如果为-1,subLR的左孩子会补为subL的右孩子,而parent的左节点无人补,parent的bf置为1
代码如下:
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = parent->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 1)
{
subL->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
}
subLR->_bf = 0;
}
4,对于RL,保存subRL的平衡因子,用于后面判断:如果为1,subRL的右孩子会补为subR的左孩子,parent的右节点无人补,是空,parent的bf置为-1,如果为-1,subRL的左孩子会补为parent的右孩子,而subR的左节点无人补,subR的bf置为1
代码如下:
void RotateRL(Node* parent) //先旋转,后调整平衡因子
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (1 == bf) //subRL的右孩子会补为subR的左孩子,parent的右节点无人补,是空,bf置为-1
{
parent->_bf = -1;
}
else if (-1 == bf) //subRL的左孩子会补为parent的右孩子,而subR的左节点无人补,bf置为1
{
subR->_bf = 1;
}
subRL->_bf = 0;
}
这样AVL树的插入就解决了,我们需要一个函数来判定该树是否是AVL树。这个简单,只需遍历整棵树,看他的平衡因子是否正确即可。代码如下:
bool IsBalance()
{
int depth = 0;
return _IsBalance(_root, depth);
}
bool _IsBalance(Node* root, int& depth)
{
if (root == NULL)
{
depth = 0;
return true;
}
int leftDepth = 0;
int rightDepth = 0;
if (_IsBalance(root->_left, leftDepth) == false)
return false;
if (_IsBalance(root->_right, rightDepth) == false)
return false;
if ((rightDepth - leftDepth) != root->_bf)
{
cout << "bf 异常" << root->_key << endl;
//return false;
}
depth = rightDepth > leftDepth ? rightDepth + 1 : leftDepth + 1;
return abs(rightDepth - leftDepth) < 2;
}
像查找,求深度等这种问题的解决就不具体讲解了,后面附有完整代码。
完整代码
#include<iostream>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K,V>* _left;
AVLTreeNode<K,V>* _right;
AVLTreeNode<K,V>* _parent;
K _key;
V _value;
int _bf; //平衡因子
AVLTreeNode(const K& key,const V& value)
:_left(NULL),_right(NULL),_parent(NULL),_key(key),_value(value),_bf(0)
{}
};
template<class K,class V>
class AVLTree
{
typedef AVLTreeNode<K,V> Node;
public:
AVLTree()
:_root(NULL)
{}
~AVLTree()
{
_Delete(_root);
}
bool Insert(const K& key,const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
return true;
}
Node* cur = _root;
Node* parent = cur;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
return false;
}
//找到插入的位置 插入
cur = new Node(key, value);
cur->_parent = parent;
if (parent->_key > key)
parent->_left = cur;
else
parent->_right = cur;
//调整平衡因子
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 = cur->_parent;
}
else // parent->_bf == 2 / == -2
{
//旋转
if (parent->_bf == 2)
{
if (cur->_bf == 1)
{
RotateL(parent);
}
else
{
RotateRL(parent);
}
}
else
{
if (cur->_bf == 1)
{
RotateLR(parent);
}
else
{
RotateR(parent);
}
}
break;
}
}
return true;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
Node* Find(const K& x)
{
return _Find(x);
}
bool IsBalance()
{
int depth = 0;
return _IsBalance(_root, depth);
}
protected:
bool _IsBalance(Node* root, int& depth) //注意:depth引用
{
if (root == NULL)
{
depth = 0;
return true;
}
int leftDepth = 0;
int rightDepth = 0;
if (_IsBalance(root->_left, leftDepth) == false)
return false;
if (_IsBalance(root->_right, rightDepth) == false)
return false;
if ((rightDepth - leftDepth) != root->_bf)
{
cout << "bf 异常" << root->_key << endl;
//return false;
}
depth = rightDepth > leftDepth ? rightDepth + 1 : leftDepth + 1;
return abs(rightDepth - leftDepth) < 2;
}
Node* _Find(Node* root, const K& x)
{
while (root)
{
if (x > root->_key)
root = root->_right;
else if (x < root->_key)
root = root->_key;
else
return root;
}
return NULL;
}
void _InOrder(Node* root)
{
if (root == NULL)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
void _Delete(Node*& root)
{
if (root == NULL)
return;
_Delete(root->_left);
_Delete(root->_right);
delete root;
root = NULL;
}
int Depth(Node* root)
{
if (root == NULL)
return 0;
int leftDepth = Depth(root->_left);
int rightDepth = Depth(root->_right);
return leftDepth > rightDepth ?leftDepth + 1 : rightDepth + 1;
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* pparent = parent->_parent;
if (pparent)
{
parent->_parent = subR;
if (pparent->_left == parent)
pparent->_left = subR;
else
pparent->_right = subR;
}
else
_root = subR;
subR->_parent = pparent;
subR->_bf = parent->_bf = 0;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* pparent = parent->_parent;
if (pparent)
{
parent->_parent = subL;
if (pparent->_left == parent)
pparent->_left = subL;
else
pparent->_right = subL;
}
else
_root = subL;
subL->_parent = pparent;
subL->_bf = parent->_bf = 0;
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = parent->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 1)
{
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
}
else
{
subL->_bf = parent->_bf = 0;
}
subLR->_bf = 0;
}
void RotateRL(Node* parent) //先旋转,后调整平衡因子
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (1 == bf)
{
subR->_bf = 0;
parent->_bf = -1;
}
else if (-1 == bf)
{
parent->_bf = 0;
subR->_bf = 1;
}
else
{
parent->_bf = subR->_bf = 0;
}
subRL->_bf = 0;
}
private:
Node* _root;
};
void Test()
{
AVLTree<int, int> t;
//int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
t.Insert(a[i], i);
cout << a[i] << "IsBalance?" << t.IsBalance() << endl;
}
t.InOrder();
cout << "IsBalance?" << t.IsBalance() << endl;
}