先声明一下这里为什么只写了AVL树节点的插入哈
- 首先说一下AVL树的查找,因为查找并没有破坏节点位置。而我们的AVL树是在搜索树的基础上限定了树的左右树之间的高度不超过(-1 || 1),所以说查找是完全类比搜索二叉树的。
- 在来说一下删除吧,因为删除是也是要考虑树的高度,还有顺序的,这个想一想就有一点麻烦,不过只要多画几张图,把分类的几种情况理清楚了,还是可以画出来的,但是要清楚一个概念就是空间换时间删除的搜索的时间是log2N,删除的时间想一想有多复杂,就有多复杂的。
好了,来主要说插入吧!
插入当中主要涉及到两个比较重要的点,一个是旋转还有一个就是平衡因子,而我们的旋转还有平衡因子为什么要改变,都是通过插入元素间接引起的。
AVL树还是主要要看图的不看图,几下子就晕了。
我们先简单的看一下这张图,主要先看一下插入节点对平衡因子的影响,黑色圈子是我插入的节点插入节点以后我们数根节点左边的高度,开始是-3,插入以后变成了-4,根节点右边一直是2,插入以后根节点平衡因子变成了-2。而追根问底从下往上寻找第一个-2产生位置在根节点左子树位置
其实我个人感觉记住低一个产生不满足条件的平衡因子是会让理解旋转很多变的方便很多的。
好了,看一下代码吧。
- 先简单的构造一下AVL树吧
#include <iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const K& key = K(), const V& value = V())
: _pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _key(key)
, _value(value)
, _bf(0)
{}
AVLTreeNode<K, V>* _pLeft;
AVLTreeNode<K, V>* _pRight;
AVLTreeNode<K, V>* _pParent;
K _key;
V _value;
int _bf; // 平衡因子
};
我们主要通过在AVL树里面放了一个数值,即键值对。
- 插入数值
bool Insert(const K& key, const V& value)
{
if (nullptr == _pRoot)
{
_pRoot = new Node(key, value);
return true;
}
// 找待插入节点的位置
PNode pCur = _pRoot;
PNode pParent = nullptr;
while (pCur)
{
pParent = pCur;
if (key < pCur->_key)
pCur = pCur->_pLeft;
else if (key > pCur->_key)
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 (-1 == pParent->_bf || 1 == pParent->_bf)
{
pCur = pParent;
pParent = pCur->_pParent;
}
else
{
// parent的平衡因子已经不满足情况
if (2 == pParent->_bf)
{
// 右子树比较高
if (1 == pCur->_bf)
RotateL(pParent);
else
RotateRL(pParent);
}
else
{
// 左子树比较高
if (-1 == pCur->_bf)
RotateR(pParent);
else
RotateLR(pParent);
}
break;
}
}
return true;
}
插入数值还是类比搜索二叉树,我们先检查这个节点是不是存在,如果存在就结束掉了,剩余就是更新平衡因子,然后通过平衡因子判断是否需要旋转。平衡因子的查看其实我们是要看三代的,**插入数(第一代) 插入树根节点(第二代) 插入树根节点的根节点(第三代)**里面内嵌的旋转函数下面会分情况讨论滴。
- 函数的旋转
void RotateR(PNode pParent)
{
PNode pSubL = pParent->_pLeft;
PNode pSubLR = pSubL->_pRight;
pSubL->_pRight = pParent;
pParent->_pLeft = pSubLR;
if (pSubLR)
pSubLR->_pParent = pParent;
PNode pPParent = pParent->_pParent;
pParent->_pParent = pSubL;
pSubL->_pParent = pPParent;
if (nullptr == pPParent)
_pRoot = pSubL;
else
{
if (pParent == pPParent->_pLeft)
pPParent->_pLeft = pSubL;
else
pPParent->_pRight = pSubL;
}
pSubL->_bf = pParent->_bf = 0;
}
void RotateL(PNode pParent)
{
PNode pSubR = pParent->_pRight;
PNode pSubRL = pSubR->_pLeft;
pSubR->_pLeft = pParent;
pParent->_pRight = pSubRL;
if (pSubRL)
pSubRL->_pParent = pParent;
PNode pPParent = pParent->_pParent;
pSubR->_pParent = pPParent;
pParent->_pParent = pSubR;
if (nullptr == pPParent)
_pRoot = pSubR;
else
{
if (pPParent->_pLeft == pParent)
pPParent->_pLeft = pSubR;
else
pPParent->_pRight = pSubR;
}
pParent->_bf = pSubR->_bf = 0;
}
void RotateLR(PNode pParent)
{
PNode pSubL = pParent->_pLeft;
PNode pSubLR = pSubL->_pRight;
int bf = pSubLR->_bf;
RotateL(pParent->_pLeft);
RotateR(pParent);
if (1 == bf)
pSubL->_bf = -1;
else if (-1 == bf)
pParent->_bf = 1;
}
void RotateRL(PNode pParent)
{
PNode pSubR = pParent->_pRight;
PNode pSubRL = pSubR->_pLeft;
int bf = pSubRL->_bf;
RotateR(pParent->_pRight);
RotateL(pParent);
if (1 == bf)
pParent->_bf = -1;
else if (-1 == bf)
pSubR->_bf = 1;
}
-
节点插入左子树左侧 右旋
需要注意的是我们的子树的根节点是否是二叉树的根节点,其他的通过二叉树搜索树的性质就可以判断了。 -
节点插入右子树右侧 左旋
-
节点在左子树右侧插入 先左旋在右旋
这个图我就直接在左旋图的基础上用箭头代表指向,其实我就是感觉这样画稍微简单一点了 -
节点在右子树左侧插入 先右旋在左旋
-
完整代码
#include <iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const K& key = K(), const V& value = V())
: _pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _key(key)
, _value(value)
, _bf(0)
{}
AVLTreeNode<K, V>* _pLeft;
AVLTreeNode<K, V>* _pRight;
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(nullptr)
{}
bool Insert(const K& key, const V& value)
{
if (nullptr == _pRoot)
{
_pRoot = new Node(key, value);
return true;
}
// 找待插入节点的位置
PNode pCur = _pRoot;
PNode pParent = nullptr;
while (pCur)
{
pParent = pCur;
if (key < pCur->_key)
pCur = pCur->_pLeft;
else if (key > pCur->_key)
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 (-1 == pParent->_bf || 1 == pParent->_bf)
{
pCur = pParent;
pParent = pCur->_pParent;
}
else
{
// parent的平衡因子已经不满足情况
if (2 == pParent->_bf)
{
// 右子树比较高
if (1 == pCur->_bf)
RotateL(pParent);
else
RotateRL(pParent);
}
else
{
// 左子树比较高
if (-1 == pCur->_bf)
RotateR(pParent);
else
RotateLR(pParent);
}
break;
}
}
return true;
}
void InOrder()
{
_InOrder(_pRoot);
}
bool IsBalanceTree()
{
return _IsBalanceTree(_pRoot);
}
private:
bool _IsBalanceTree(PNode pRoot)
{
if (nullptr == pRoot)
return true;
int leftHeight = _Height(pRoot->_pLeft);
int rightHeight = _Height(pRoot->_pRight);
int diff = rightHeight - leftHeight;
if (abs(diff) > 1 || diff != pRoot->_bf)
return false;
return _IsBalanceTree(pRoot->_pLeft) && _IsBalanceTree(pRoot->_pRight);
}
int _Height(PNode pRoot)
{
if (nullptr == pRoot)
return 0;
int leftHeight = _Height(pRoot->_pLeft);
int rightHeight = _Height(pRoot->_pRight);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
void _InOrder(PNode pRoot)
{
if (pRoot)
{
_InOrder(pRoot->_pLeft);
cout << "<" << pRoot->_key << "," << pRoot->_value << ">" << endl;
_InOrder(pRoot->_pRight);
}
}
void RotateR(PNode pParent)
{
PNode pSubL = pParent->_pLeft;
PNode pSubLR = pSubL->_pRight;
pSubL->_pRight = pParent;
pParent->_pLeft = pSubLR;
if (pSubLR)
pSubLR->_pParent = pParent;
PNode pPParent = pParent->_pParent;
pParent->_pParent = pSubL;
pSubL->_pParent = pPParent;
if (nullptr == pPParent)
_pRoot = pSubL;
else
{
if (pParent == pPParent->_pLeft)
pPParent->_pLeft = pSubL;
else
pPParent->_pRight = pSubL;
}
pSubL->_bf = pParent->_bf = 0;
}
void RotateL(PNode pParent)
{
PNode pSubR = pParent->_pRight;
PNode pSubRL = pSubR->_pLeft;
pSubR->_pLeft = pParent;
pParent->_pRight = pSubRL;
if (pSubRL)
pSubRL->_pParent = pParent;
PNode pPParent = pParent->_pParent;
pSubR->_pParent = pPParent;
pParent->_pParent = pSubR;
if (nullptr == pPParent)
_pRoot = pSubR;
else
{
if (pPParent->_pLeft == pParent)
pPParent->_pLeft = pSubR;
else
pPParent->_pRight = pSubR;
}
pParent->_bf = pSubR->_bf = 0;
}
void RotateLR(PNode pParent)
{
PNode pSubL = pParent->_pLeft;
PNode pSubLR = pSubL->_pRight;
int bf = pSubLR->_bf;
RotateL(pParent->_pLeft);
RotateR(pParent);
if (1 == bf)
pSubL->_bf = -1;
else if (-1 == bf)
pParent->_bf = 1;
}
void RotateRL(PNode pParent)
{
PNode pSubR = pParent->_pRight;
PNode pSubRL = pSubR->_pLeft;
int bf = pSubRL->_bf;
RotateR(pParent->_pRight);
RotateL(pParent);
if (1 == bf)
pParent->_bf = -1;
else if (-1 == bf)
pSubR->_bf = 1;
}
private:
PNode _pRoot;
};
void TestAVLTree()
{
//int array[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15};
int array[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
AVLTree<int, int> t;
for (auto e : array)
{
t.Insert(e, e);
}
t.InOrder();
if (t.IsBalanceTree())
{
cout << "t is AVL tree!!!" << endl;
}
else
{
cout << "t is not AVL tree!!!" << endl;
}
}
int main()
{
TestAVLTree();
return 0;
}
验证一下结果