···AVL树又称为高度平衡的二叉树。它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度。
···AVL树有以下几条性质:
·····1.左子树和右子树的高度之差的绝对值不超过1
·····2.树中的每个左子树和右子树都是AVL树
·····3.每个节点都有一个平衡因子,任一节点的平衡因子是-1,1,0.(每个节点的平衡因子等于右子树的高度减去左子树的高度)
···AVL树就是在二叉搜索树的基础上实现的,所以这里主要描述AVL树的旋转过程,最后会附上完整的源代码。
AVL树在进行插入时,要不断更新每个节点的平衡因子,如果插入叶子节点后,父节点的平衡因子变为0,则不用调整。如果父节点的平衡因子变为1或-1,需要调整吗?注意这里虽然父节点的平衡因子是1或-1,满足AVL树的性质,但是它可能会影响上一层的节点,画图说明一下。
···插入B节点后,图一图二中的A节点平衡因子都变为-1,图一已经是AVL树,但是图二根节点的平衡因子变为-2,所有插入节点后,如果父节点的平衡 因子变成1或-1,需要继续向上调整。
如果插入节点后父节点的平衡因子变为2或-2,需要立即旋转来调整平衡因子。
右单旋
··· 在判断旋转的方式时,最好先标出每个节点的平衡因子(三角形节点是叶节点),这种情况下就要进行右单旋了,我在记忆右单旋的时候就将其理解为:将要旋转的节点变成它左孩子节点的右子树,在此图中,就是把30这个节点变成20的右子树,那么20已经有右孩子了,怎么办呢?很简单,依据二叉搜索树的性质,所有节点都遵循左孩子值比它小,右孩子值比它大这一原则,所以f节点的值大于20,而f的值一定小于30,所以就把f作为30的左子树,然后将30作为20的右子树,就完成右单旋了。
这就是旋转后的AVL树。
左单旋
和右单旋一样,先标记平衡因子
再把10这个节点转到20的左边就行了
左右双旋
什么时候需要进行左右双旋呢?
同样的,我们需要先标记平衡因子,当parent和subl的平衡因子分别为-2和1时,就要进行左右双旋了。
双旋需要考虑三种情况(sublr的平衡因子调整前分别为0,-1,1时),如下图
1.
第一种情况最简单,先让sublr的左孩子指向subl,再让parent变成sublr的右孩子即可。旋转后的三个节点平衡因子都是0.(左右双旋第一步应该先左旋subl,再右旋parent)
上图就是旋转过程。
2.
这种情况下调整前sublr的平衡因子为-1,调整后,parent,subl,sublr的平衡因子分别为1, 0, 0.
图为调整后的AVL树
3.
这种情况下调整前sublr的平衡因子是1,调整后parent,subl,sublr的平衡因子分别为0,-1,0。
右左双旋
与左右双旋相对应,当parent和subr的平衡因子分别为2,-1时进行右左双旋
右左双旋的步骤是先对subr进行右旋,再对parent进行左旋。
同样分为三种情况:
1.
这种情况调整前subrl的平衡因子为0,调整后,parent,subr,subrl的平衡因子都是0
调整后如图
2.第二种情况调整前subrl的平衡因子是1,调整后parent,subr,subrl分别是-1,0,0
调整后:
3.第三钟情况:调整前subrl的平衡因子是-1,调整后parent,subr,subrl分别是0,1,0
调整后:
源代码:
#pragma once
#include<iostream>
#include<cstdlib>
#include <algorithm>
#include<cassert>
using namespace std;
template<typename K, typename V>
struct AVLTreeNode
{
typedef AVLTreeNode<K, V> Node;
AVLTreeNode(const K& key, const V& value)
: _left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _bf(0)
{}
Node* _left;
Node* _right;
Node* _parent;
int _bf;
K _key;
V _value;
};
template<typename K, typename V>
class AVLTree
{
public:
typedef AVLTreeNode<K, V> Node;
//构造
AVLTree()
:_root(NULL)
{}
//析构
~AVLTree()
{
_Destroy(_root);
}
//插入节点
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
return true;
}
Node* parent = NULL;
Node* cur = _root;
while (NULL != cur)
{
parent = cur;
if (key > cur->_key)
{
cur = cur->_right;
}
else if(key < cur->_key)
{
cur = cur->_left;
}
else //因为搜索树不存在相同的值,所以返回错误
{
return false;
}
}
cur = new Node(key, value);
if (cur->_key > parent->_key)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//插入完成,更新平衡因子
while (parent)
{
if (parent->_left == cur)
{
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 || parent->_bf == -2)
{
if (parent->_bf == 2)
{
if (cur->_bf == 1) //左单旋
{
_RotateL(parent);
}
else //右左旋转
{
_RotateRL(parent);
}
}
if(parent->_bf == -2)
{
if (cur->_bf == 1) //左右旋转
{
_RotateLR(parent);
}
else //右单旋
{
_RotateR(parent);
}
}
break;//
}
}
}
void _RotateL(Node* parent)
{
assert(parent);
Node* ppNode = parent->_parent;
Node* prNode = parent->_right;
Node* prlNode = prNode->_left;
parent->_right = prlNode; //***
if (prlNode)
{
prlNode->_parent = parent;
}
prNode->_left = parent;
parent->_parent = prNode;
if (ppNode == NULL)
{
_root = prNode;
prNode->_parent = NULL;
}
else
{
if (parent == ppNode->_left)
{
ppNode->_left = prNode;
}
else
{
ppNode->_right = prNode;
}
prNode->_parent = ppNode;
}
parent->_bf = prNode->_bf = 0;
}
void _RotateR(Node* parent)
{
assert(parent);
Node* ppNode = parent->_parent;
Node* plNode = parent->_left;
Node* plrNode = plNode->_right;
parent->_left = plrNode;
if (plrNode)
{
plrNode->_parent = parent;
}
plNode->_right = parent;
parent->_parent = plNode;
if (ppNode == NULL)
{
_root = plNode;
plNode->_parent = NULL;
}
else
{
if (parent == ppNode->_left)
{
plNode = ppNode->_left;
}
else
{
plNode = ppNode->_right;
}
plNode->_parent = ppNode;
}
parent->_bf = plNode->_bf = 0;
}
void _RotateLR(Node *parent)
{
Node* SubL = parent->_left;
Node* SubLR = SubL->_right;
int bf = SubLR->_bf;
_RotateL(SubL);
_RotateR(parent);
//如果bf为0,代表插入点就是这个节点,这个时候所有旋转后的bf皆为0
if (bf == 0)
{
SubL->_bf = parent->_bf = 0;
}
//当bf为1时,这个时候相当于是给sublr的右树插入
else if (bf == 1)
{
SubL->_bf = -1;
parent->_bf = 0;
}
//bf是-1时,相当于给sublr的左树插入
else
{
SubL->_bf = 0;
parent->_bf = 1;
}
SubLR->_bf = 0;
}
void _RotateRL(Node *parent)
{
Node* SubR = parent->_right;
Node* SubRL = SubR->_left;
int bf = SubRL->_bf;
_RotateR(SubR);
_RotateL(parent);
if (bf == 0)
{
SubR->_bf = parent->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
SubR->_bf = 1;
}
else
{
SubR->_bf = 0;
parent->_bf = -1;
}
SubRL->_bf = 0;
}
bool _Find(const K& key)
{
if (_root == NULL)
return false;
Node* cur = _root;
while (cur)
{
if (key > cur->_key)
{
cur = cur->_right;
}
else if (key > cur->_key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
int _Height(Node* root)
{
if (root == NULL)
{
return 0;
}
int LeftLen = _Height(root->_left);
int RightLen = _Height(root->_right);
return LeftLen > RightLen ? LeftLen + 1 : RightLen + 1;
}
O(N^2)
//bool _IsBalance(Node* root)
//{
// if (root == NULL)
// {
// return true;
// }
// int left = _Height(root->_left);
// int right = _Height(root->_right);
// int diff = left - right;
// if (diff > 1 || diff < -1)
// {
// return false;
// }
// return _IsBalance(root->_left) && _IsBalance(root->_right);
//}
bool _IsBalance2(Node* root, int &height)
{
if (root == NULL)
{
height = 0;
return true;
}
int leftHeight = 0, rightHeight = 0;
bool leftRet = _IsBalance2(root->_left, leftHeight);
bool rightRet = _IsBalance2(root->_right, rightHeight);
height = max(leftHeight, rightHeight) + 1;
if (abs(leftHeight - rightHeight) > 1)
{
return false;
}
return leftRet && rightRet;
}
bool IsBalance()
{
int height = 0;
return _IsBalance2(_root, height);
}
void _Destroy(Node* root)
{
if (root == NULL)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
root = NULL;
}
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
cout << root->_key<< "->" << endl;
_InOrder(root->_right);
}
void InOrder()
{
_InOrder(_root);
}
private:
Node * _root;
//拷贝构造
AVLTree(const AVLTree<K, V> & a);
//赋值
AVLTree<K, V>& operator=(const AVLTree<K, V> & a);
};
void test()
{
AVLTree<int, int> AVLtree;
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
AVLtree.Insert(a[i], a[i]);
}
AVLtree.InOrder();
bool ret = AVLtree.IsBalance();
if (ret)
{
cout << "yes" << endl;
}
else
{
cout << "no" << endl;
}
}