AVL树:
AVL树也成为平衡二叉树,它是这样定义的:
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
1、它的左右子树都是AVL树
2、左子树和右子树高度之差(简称平衡因子)的绝对值不超过1(-1、0、1)
AVL树的插入:
在插入节点后会造成父节点的平衡因子发生改变,需要从下往上更新平衡因子,若某一节点的平衡因子的绝对值大于1,说明以这个结点为根的树已经不平衡,此时就要去通过旋转来让数重新达到平衡状态。
旋转规则:
左单旋:在较高右子树的右侧插入了结点
右单旋:在较高左子树的左侧插入了结点
先左后右:在较高左子树的右侧插入了结点
先右后左:在较高右子树的左侧插入了结点
对于较高子树的理解:
较高子树就是不平衡树中的高度较大的子树。
下面是通过右左旋转达到平衡和通过左旋转达到平衡的例子:
下面是通过左右旋转达到平衡和通过右旋转达到平衡的例子:
通过上面的例子我们可以得到以下结论:
当一棵树不平衡时,如果这棵树根节点和其平衡因子不为0的结点的平衡因子符号相同则通过一次旋转即可重新平衡,否则就需要两次旋转。
根为2,子节点为1,通过左旋转即可平衡
根为2,子节点为-1,通过右左旋转才能平衡
根为-2,子节点为1,通过左右旋转才能平衡
根为-2,子节点为-1,通过右旋转即可平衡
注意:在旋转完成之后记得要把平衡因子修改为适当的值,可以通过画出图片做以分析,得到规律
代码:
#include<iostream>
#include<windows.h>
using namespace std;
template<typename K, typename V>
struct AVLTreeNode
{
AVLTreeNode()
{}
AVLTreeNode(const K& _key, const V& _value = V())
: key(_key)
, value(_value)
, bf(0)
, pLeft(NULL)
, pRight(NULL)
, pParent(NULL)
{}
K key;
V value;
int bf;
AVLTreeNode *pLeft;
AVLTreeNode *pRight;
AVLTreeNode *pParent;
};
template<typename K, typename V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
AVLTree()
:pRoot(NULL)
{}
bool Inserter(const K& _key)
{
//
Node* pCur = pRoot;
Node* parent = NULL;
if (NULL == pRoot)
{
pRoot = new Node(_key);
return true;
}
else
{
//找到插入位置
while (pCur)
{
if (pCur->key < _key)
{
parent = pCur;
pCur = pCur->pRight;
}
else if (pCur->key > _key)
{
parent = pCur;
pCur = pCur->pLeft;
}
else
return false;
}
//插入结点
pCur = new Node(_key);
if (parent->key > _key)
{
parent->pLeft = pCur;
}
else
parent->pRight = pCur;
pCur->pParent = parent;
}
//自下向上更新平衡因子
while (parent)
{
//更新当前结点父节点的平衡因子
if (parent->pLeft == pCur)
{
parent->bf--;
}
else
{
parent->bf++;
}
//如果其父节点的平衡因子为0,则说明达到平衡
if (0 == parent->bf)
{
break;
}
//如果是1,则继续向上更新
else if (1 == parent->bf || -1 == parent->bf)
{
pCur = parent;
parent = pCur->pParent;
}
//不是1,就可能是+-2,此时子树不平衡需要调整
//一旦parent的因子绝对值==2,说明其需要调整,此时较高子树是相对于它而言的
else
{
//右子树高
if (parent->bf == 2)
{
//右子树的右侧高
if (pCur->bf == 1)
{
//左旋转
RotateLeft(parent);
break;
}
//右子树的左侧高
else
{
//右左旋转
RotateRL(pCur);
break;
}
}
//左子树高
else
{
//左子树的左侧高
if (pCur->bf == -1)
{
//右旋
RotateRight(parent);
break;
}
//左子树的右侧高
else
{
//左右旋转
RotateLR(pCur);
break;
}
}
}
}
return true;
}
bool IsBalanceTree()//判断树是不是AVL树
{
return _IsBalanceTree(pRoot);
}
int Hight()//求书的高度
{
return _Hight(pRoot);
}
void InOrder()
{
_InOrder(pRoot);
cout << endl;
}
private:
bool _IsBalanceTree(Node *pRoot)
{
if (NULL == pRoot)
return true;
int left = _Hight(pRoot->pLeft);
int right = _Hight(pRoot->pRight);
if (pRoot->bf != (right - left) || std::abs(pRoot->bf) > 1)
return false;
return _IsBalanceTree(pRoot->pLeft) && _IsBalanceTree(pRoot->pRight);
}
void _InOrder(Node* pRoot)
{
if (NULL == pRoot)
return;
_InOrder(pRoot->pLeft);
cout << pRoot->key << " ";
_InOrder(pRoot->pRight);
}
int _Hight(Node* pRoot)
{
if (NULL == pRoot)
return 0;
if (NULL == pRoot->pLeft && NULL == pRoot->pRight)
return 1;
int left = _Hight(pRoot->pLeft)+1;
int right = _Hight(pRoot->pRight)+1;
return left > right ? left : right;
}
//左旋---->就是用父节点的右孩子去替换父节点,将父节点连接在其右孩子的左侧
void RotateLeft(Node *parent)
{
Node* pParent = parent->pParent;
Node* pSubR = parent->pRight;
Node* pSubRL = pSubR->pLeft;
//父节点的右链接右孩子的左结点
parent->pRight = pSubRL;
//右孩子成为父节点的父节点
parent->pParent = pSubR;
//右孩子的左结点存在,更新其父节点
if (pSubRL)
pSubRL->pParent = parent;
//更新右孩子的父节点和左结点
pSubR->pParent = pParent;
pSubR->pLeft = parent;
//如果pParent存在
if (pParent)
{
//说明这是一颗子树
//将右节点连接在pParent的左或者右
if (pParent->pLeft == parent)
{
pParent->pLeft = pSubR;
}
else
{
pParent->pRight = pSubR;
}
}
//pParent不存在,说明父节点是树根
else//这是树根将变为右节点
pRoot = pSubR;
//将其平衡因子置0
parent->bf = pSubR->bf = 0;
}
//右旋
void RotateRight(Node* parent)
{
Node* pParent = parent->pParent;
Node* pSubL = parent->pLeft;
Node* pSubLR = pSubL->pRight;
parent->pLeft = pSubLR;
parent->pParent = pSubL;
if (pSubLR)
pSubLR->pParent = parent;
pSubL->pParent = pParent;
pSubL->pRight = parent;
if (pParent)
{
if (pParent->pLeft == parent)
pParent->pLeft = pSubL;
else
pParent->pRight = pSubL;
}
else
{
pRoot = pSubL;
}
parent->bf = pSubL->bf = 0;
}
//左右旋转
void RotateLR(Node* parent)
{
//判断其右孩子的平衡因子
int bf = parent->pRight->bf;
//parent左旋,parent下降其父节点成为其父节点的父节点
RotateLeft(parent);
//parent之前的父节点右旋
RotateRight(parent->pParent->pParent);
if (bf == -1)
{//说明parent接受了其右孩子的左孩子,
parent->pParent->pRight->bf = 1;
}
else if (1 == bf)
{
//说明parent的父节点,接受了其右孩子的右孩子
parent->bf = -1;
}
}
//右左旋转
void RotateRL(Node* parent)
{
int bf = parent->pLeft->bf;
RotateRight(parent);
RotateLeft(parent->pParent->pParent);
if (1 == bf)
{
parent->pParent->pLeft->bf = -1;
}
else if (-1 == bf)
{
parent->bf = 1;
}
}
protected:
Node* pRoot;
};