什么是AVL树呢?(概念)
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
1、它的左右子树都是AVL树
2、左子树和右子树高度之差(简称平衡因子)的绝对值不超过1(-1、0、1)
3、如果一棵二叉搜索树是高度平衡的,它就是AVL树。
4、时间复杂度:如果它有n个结点,其高度可保持在O(lgn),平均搜索时间复杂度O(lg(n))
首先,创建AVL树
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const K& key, const V& value)
: _pRight(NULL)
, _pLeft(NULL)
, _pParent(NULL)
, _key(key)
, _value(value)
, _bf(0)
{}
AVLTreeNode<K, V>* _pRight;
AVLTreeNode<K, V>* _pLeft;
AVLTreeNode<K, V>* _pParent;
K _key;
V _value;
int _bf;//当前节点的平衡因子
};
二、再来分析如何插入结点,使得成为AVL树
在AVL树中插入结点(key,value)的算法:
1. 如果是空树,插入后即为根节点,插入后直接返回true;
2. 如果树不空,寻找插入位置,若在寻找的过程中找到key,则插入失败直接返回false;
3. 插入结点;
4. 更新平衡因子,对树进行调整;
相应代码:
bool Insert(const K& key, const V& value)
{
//空树
if (NULL == _pRoot)
{
_pRoot = new Node(key, value);
return true;
}
//不为空,1 找插入位置
pNode pCur = _pRoot;//从根的位置开始找
pNode pParent = NULL;//刚开始根节点无双亲节点
while (pCur)
{
if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (key>pCur->_key)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else
return false;
}
//插入节点
pCur = new Node(key, value);
if (key < pParent->_key)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
pCur->_pParent = pParent;
//更新平衡因子
while (pParent)
{
//插入分情况
if (pParent->_pLeft == pCur)
pParent->_bf--;
else
pParent->_bf++;
//更新完成以后需要平衡(分情况)
if (0 == pParent->_bf)
break;
else if (pParent->_bf == 1 || pParent->_bf == -1)
{
pCur = pParent;
pParent = pCur->_pParent;
}
else//2或者-2 //需要单旋或者双旋完成平衡
{
if (pParent->_bf == 2)
{
if (pCur->_bf == 1)//左旋
RoteteL(pParent);
else
RoteteRL(pParent);//右左旋
}
else
{
if (pCur->_bf == -1)
RoteteR(pParent);
else
RoteteLR(pParent);
}
break;//不再向上调整
}
}
return true;
}
三、平衡化旋转
如果在一棵原本是平衡的二叉搜索树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。
下面一一介绍四种旋转
1.左单旋(插入点位于ptr的右子节点的右子树--右右)
代码实现:
void RoteteL(pNode pParent)
{
pNode pSubR = pParent->_pRight;
pNode pSubRL = pSubR->_pLeft;
//提升因子
pParent->_pRight = pSubRL;
if (pSubRL)
pSubRL->_pParent = pParent;
pNode PParent = pParent->_pParent;
pSubR->_pLeft = pParent;
pSubR->_pParent = PParent;
pParent->_pParent = pSubR;
//pParent有三种情况(根/位于父亲的左,父亲的右)
if (pParent == _pRoot)
_pRoot = pSubR;
if (PParent)
{
if (pParent == PParent->_pLeft)
PParent->_pLeft = pSubR;
else
PParent->_pRight = pSubR;
}
//更新平衡因子
pParent->_bf = 0;
pSubR->_bf = 0;
}
2.右单旋(插入点位于ptr的左子结点的左子树--左左)
代码实现:
void RoteteR(pNode pParent)
{
pNode pSubL = pParent->_pLeft;
pNode pSubLR = pSubL->_pRight;
pParent->_pLeft = pSubLR;
if (pSubLR)
pSubLR->_pParent = pParent;
pNode PParent = pParent->_pParent;
pSubL->_pRight = pParent;
pParent->_pParent = pSubL;
pSubL->_pParent = PParent;
if (pParent == _pRoot)
_pRoot = pSubL;
if (PParent)
{
if (pParent == PParent->_pLeft)
PParent->_pLeft = pSubL;
else
PParent->_pRight = pSubL;
}
pParent->_bf = 0;
pSubL->_bf = 0;
}
3.左右双旋(插入点位于ptr左子节点的右子树--左右)
代码实现:
void RoteteLR(pNode pParent)
{
int bf = pParent->_pLeft->_pRight->_bf;
RoteteL(pParent->_pLeft);
RoteteR(pParent);
//更新平衡因子
if (bf == 1)
{
pParent->_bf = 0;
pParent->_pLeft->_bf = -1;
pParent->_pLeft->_pRight->_bf = 0;
}
else if (bf == -1)
{
pParent->_bf = 1;
pParent->_pLeft->_bf = 0;
pParent->_pLeft->_pRight->_bf = 0;
}
}
4.右左双旋(插入点位于ptr右子节点的左子树--右左)
代码实现:
void RoteteRL(pNode pParent)
{
int bf = pParent->_pRight->_pLeft->_bf;
RoteteR(pParent->_pRight);
RoteteL(pParent);
//更新平衡因子
if (bf == -1)
{
pParent->_pRight->_bf = 1;
pParent->_bf = 0;
pParent->_pRight->_pLeft->_bf = 0;
}
else if (bf == 1)
{
pParent->_bf = -1;
pParent->_pRight->_bf = 0;
pParent->_pParent->_pLeft->_bf=0;
}
}
四、判断是否平衡
代码实现:
bool Isblance(pNode pRoot)
{
if (pRoot == NULL)
return true;
size_t LeftHeight = Height(pRoot->_pLeft);
size_t RightHeight = Height(pRoot->_pRight);
int height = RightHeight - LeftHeight;
return ((abs(height)<2) && Isblance(pRoot->_pLeft) && Isblance(pRoot->_pRight));
}
附录:完整代码(包含测试代码)
#pragma once
#include <iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const K& key, const V& value)
: _pRight(NULL)
, _pLeft(NULL)
, _pParent(NULL)
, _key(key)
, _value(value)
, _bf(0)
{}
AVLTreeNode<K, V>* _pRight;
AVLTreeNode<K, V>* _pLeft;
AVLTreeNode<K, V>* _pParent;
K _key;
V _value;
int _bf;//当前节点的平衡因子
};
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
typedef Node* pNode;
public:
AVLTree()
:_pRoot(NULL)
{}
void PerInoder()
{
_PerInoder(_pRoot);
cout << endl;
}
void _PerInoder(pNode pRoot)
{
if (pRoot)
{
cout << pRoot->_key << " ";
_PerInoder(pRoot->_pLeft);
_PerInoder(pRoot->_pRight);
}
}
bool Insert(const K& key, const V& value)
{
//空树
if (NULL == _pRoot)
{
_pRoot = new Node(key, value);
return true;
}
//不为空,1 找插入位置
pNode pCur = _pRoot;//从根的位置开始找
pNode pParent = NULL;//刚开始根节点无双亲节点
while (pCur)
{
if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (key>pCur->_key)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else
return false;
}
//插入节点
pCur = new Node(key, value);
if (key < pParent->_key)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
pCur->_pParent = pParent;
//更新平衡因子
while (pParent)
{
//插入分情况
if (pParent->_pLeft == pCur)
pParent->_bf--;
else
pParent->_bf++;
//更新完成以后需要平衡(分情况)
if (0 == pParent->_bf)
break;
else if (pParent->_bf == 1 || pParent->_bf == -1)
{
pCur = pParent;
pParent = pCur->_pParent;
}
else//2或者-2 //需要单旋或者双旋完成平衡
{
if (pParent->_bf == 2)
{
if (pCur->_bf == 1)//左旋
RoteteL(pParent);
else
RoteteRL(pParent);//右左旋
}
else
{
if (pCur->_bf == -1)
RoteteR(pParent);
else
RoteteLR(pParent);
}
break;//不再向上调整
}
}
return true;
}
void RoteteL(pNode pParent)
{
pNode pSubR = pParent->_pRight;
pNode pSubRL = pSubR->_pLeft;
//提升因子
pParent->_pRight = pSubRL;
if (pSubRL)
pSubRL->_pParent = pParent;
pNode PParent = pParent->_pParent;
pSubR->_pLeft = pParent;
pSubR->_pParent = PParent;
pParent->_pParent = pSubR;
//pParent有三种情况(根/位于父亲的左,父亲的右)
if (pParent == _pRoot)
_pRoot = pSubR;
if (PParent)
{
if (pParent == PParent->_pLeft)
PParent->_pLeft = pSubR;
else
PParent->_pRight = pSubR;
}
//更新平衡因子
pParent->_bf = 0;
pSubR->_bf = 0;
}
void RoteteR(pNode pParent)
{
pNode pSubL = pParent->_pLeft;
pNode pSubLR = pSubL->_pRight;
pParent->_pLeft = pSubLR;
if (pSubLR)
pSubLR->_pParent = pParent;
pNode PParent = pParent->_pParent;
pSubL->_pRight = pParent;
pParent->_pParent = pSubL;
pSubL->_pParent = PParent;
if (pParent == _pRoot)
_pRoot = pSubL;
if (PParent)
{
if (pParent == PParent->_pLeft)
PParent->_pLeft = pSubL;
else
PParent->_pRight = pSubL;
}
pParent->_bf = 0;
pSubL->_bf = 0;
}
void RoteteLR(pNode pParent)
{
int bf = pParent->_pLeft->_pRight->_bf;
RoteteL(pParent->_pLeft);
RoteteR(pParent);
//更新平衡因子
if (bf == 1)
{
pParent->_bf = 0;
pParent->_pLeft->_bf = -1;
pParent->_pLeft->_pRight->_bf = 0;
}
else if (bf == -1)
{
pParent->_bf = 1;
pParent->_pLeft->_bf = 0;
pParent->_pLeft->_pRight->_bf = 0;
}
}
void RoteteRL(pNode pParent)
{
int bf = pParent->_pRight->_pLeft->_bf;
RoteteR(pParent->_pRight);
RoteteL(pParent);
//更新平衡因子
if (bf == -1)
{
pParent->_pRight->_bf = 1;
pParent->_bf = 0;
pParent->_pRight->_pLeft->_bf = 0;
}
else if (bf == 1)
{
pParent->_bf = -1;
pParent->_pRight->_bf = 0;
pParent->_pParent->_pLeft->_bf=0;
}
}
void MidOrder()
{
cout << "MidOrder: ";
_MidOrder(_pRoot);
cout << endl;
}
bool _Isblance()
{
return Isblance(_pRoot);
}
bool Isblance(pNode pRoot)
{
if (pRoot == NULL)
return true;
size_t LeftHeight = Height(pRoot->_pLeft);
size_t RightHeight = Height(pRoot->_pRight);
int height = RightHeight - LeftHeight;
return ((abs(height)<2) && Isblance(pRoot->_pLeft) && Isblance(pRoot->_pRight));
}
size_t Height(pNode pRoot)
{
if (NULL == pRoot)
return 0;
else if (NULL == pRoot->_pLeft&&NULL == pRoot->_pRight)
return 1;
else
return Height(pRoot->_pLeft) > Height(pRoot->_pRight) ?
Height(pRoot->_pLeft) + 1 : Height(pRoot->_pRight) + 1;
}
private:
pNode _pRoot;
void _MidOrder(pNode& pRoot)
{
if (pRoot)
{
_MidOrder(pRoot->_pLeft);
cout << pRoot->_key << " ";
_MidOrder(pRoot->_pRight);
}
}
};
int main()
{
int arr[] = {16,3,7,11,9,26,18,14,15};
AVLTree<int, int> avl;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
avl.Insert(arr[i], arr[i]);
}
if (avl._Isblance())
{
cout << "blance\n" << endl;
}
else
{
cout << "noblance\n" << endl;
}
avl.MidOrder();
avl.PerInoder();
getchar();
return 0;
}