高度平衡的搜索二叉树
一棵平衡树,或是空树,或是具有以下性质的二叉搜索树:左子树和右子树都是AVL树,且左右子树的高度之差的绝对值不超过1。
该二叉树,根结点的右子树高度为3,左子树高度为2。结点上方的数字为平衡因子,因为右子树高度比左子树高度大1,所以根结点的平衡因子为1。
一颗平衡二叉树,如果有n个结点,其高度可保持O(log2^n),平均搜索长度也可以保持在O(log2^n)
AVL树相较于普通的二叉搜索树,自主要的就是做了平衡化处理,使得二叉树变的平衡,高度降低。
在插入一个结点后应该沿搜索路径将路径上的结点平衡因子进行修改,当平衡因子大于1时,就需要进行平衡化处理。从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点,如果这三个结点在一条直线上,则采用单旋转进行平衡化,如果这三个结点位于一条折线上,则采用双旋转进行平衡化。
动图演示,图片内容可以无视,看懂操作进行了
将右子树的左子树链接到父亲节点的右孩子结点,父亲节点作为ptr结点的左孩子结点便完成了旋转。
右单旋是左单旋的镜像旋转.
当前节点ptr,与父亲节点和当前节点的左孩子结点位于一条直线上时,使用右单旋进行平衡。
当在ptr的左子树的右子树中插入一个结点后,造成了ptr平衡因子为-2的不平衡,将ptr向下找到当前结点的左孩子的右孩子,先进行左单旋ptr->left = subL,然后将ptr的右子树断开指向subR,此时便完成了旋转,最后将平衡因子进行更新。
先右单旋再左单旋,是先左后右的镜像旋转,这里就不做赘述了。
代码实现
#include<stack>
#include<iostream>
using namespace std;
template<class K,class V>
struct AVLNode
{
AVLNode<K, V> * _pLeft;
AVLNode<K, V> * _pRight;
K key;
V value;
int bf;
AVLNode()
:_pLeft(NULL)
, _pRight(NULL)
{}
AVLNode(const K key, const V value)
:_pLeft(NULL)
, _pRight(NULL)
, key(key)
, value(value)
, bf(0)
{}
};
template<class K,class V>
class AVLTree
{
//typedef AVLNode Node;
//typedef AVLNode * PNode;
public:
// 构造函数--无参
AVLTree()
:_pRoot(NULL)
{}
////构造函函数--含参
//AVLTree(const K key, const V value)
//{}
// 插入函数
bool Insert(const K key, const V value)
{
return _Insert(key, value, _pRoot);
}
// 显示函数
void showTree()
{
_showTree(_pRoot);
}
// 删除函数
bool Remove(K key)
{
return Remove(_pRoot, key);
}
private:
AVLNode<K, V> * _pRoot;
// 插入函数
bool _Insert(const K key, const V value, AVLNode<K, V> *& ptr)
{
AVLNode<K, V> * pCur = ptr;
AVLNode<K, V> *& pParent = _pRoot; // ???????????????????????????????????????????
stack<AVLNode<K, V> *> s;
while (pCur != NULL)
{
if (pCur->key == key)
return false;
pParent = pCur;
s.push(pParent);
if (pCur->key > key)
{
pCur = pCur->_pLeft;
}
else if (pCur->key < key)
{
pCur = pCur->_pRight;
}
}
// 所插位置为NULL 新建结点
pCur = new AVLNode<K, V>(key, value);
if (pCur == NULL)
{
cerr << "存储空间不足!" << endl;
exit(1);
}
// 判断是否为空树
if (pParent == NULL)
{
ptr = pCur;
return true;
}
if (key < pParent->key)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
// 调整平衡
while (s.empty() == false)
{
pParent = s.top();
s.pop();
if (pCur == pParent->_pLeft)
pParent->bf--;
else
pParent->bf++;
if (pParent->bf == 0)
break;
if (pParent->bf == 1 || pParent->bf == -1)
pCur = pParent;
if (pParent->bf == 2 || pParent->bf == -2)
{
// 进行调整
int d;// 调整平衡因子
d = (pParent->bf < 0) ? -1 : 1;
if (pCur->bf == d)
{
if (d == -1)
RotateR(pParent); // 右单旋
else
RotateL(pParent); // 左单旋
}
else
{
if (d == -1)
RotateLR(pParent); // 左右双旋
else
RotateRL(pParent); // 右左双旋
}
break;
}
if (s.empty() == true)
pCur = pParent;
else
{
AVLNode<K, V> * q;
q = s.top();
if (q->key > pParent->key)
q->_pLeft = pParent;
else
q->_pRight = pParent;
}
}
return true;
}
// 左单旋
void RotateL(AVLNode<K, V> *& ptr)
{
// 右子树比左子树高
// 对以ptr为根的AVL树做左单旋转,旋转后新根在ptr
AVLNode<K, V> * subL = ptr; // 要左旋的结点
ptr = subL->_pRight;
subL->_pRight = ptr->_pLeft;
ptr->_pLeft = subL;
ptr->bf = subL->bf = 0;
}
// 右单旋
void RotateR(AVLNode<K, V> *& ptr)
{
// 左子树比右子树高
AVLNode<K, V> * subR = ptr; // 要右旋的结点
ptr = ptr->_pLeft;
subR->_pLeft = ptr->_pRight;
ptr->_pRight = subR;
ptr->bf = subR->bf = 0;
}
// 先左再右单旋
void RotateLR(AVLNode<K, V> *& ptr)
{
AVLNode<K, V> * subL = ptr->_pLeft;
AVLNode<K, V> * subR = ptr;
ptr = subL->_pRight;
subL->_pRight = ptr->_pLeft;
ptr->_pLeft = subL;
if (ptr->bf < 0)
{
subL->bf = 0;
}
else
subL->bf = -1;
subR->_pLeft = ptr->_pRight;
ptr->_pRight = subR;
if (ptr->bf == -1)
subR->bf = 1;
else
subR->bf = 0;
ptr->bf = 0;
}
// 先右后左旋转
void RotateRL(AVLNode<K, V> *& ptr)
{
AVLNode<K, V> * subL = ptr;
AVLNode<K, V> * subR = ptr->_pRight;
ptr = ptr->_pLeft;
subR->_pLeft = ptr->_pRight;
ptr->_pRight = subR;
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
subL->_pRight = ptr->_pLeft;
ptr->_pLeft = subL;
if (ptr->bf == 1)
subL->bf = -1;
else
subL->bf = 0;
ptr->bf = 0;
}
// 显示函数
void _showTree(AVLNode<K, V> * ptr)
{
if (ptr == NULL)
return;
_showTree(ptr->_pLeft);
cout << ptr->key << " ";
_showTree(ptr->_pRight);
}
// 删除结点
bool Remove(AVLNode<K, V> *& ptr, K key)
{
AVLNode<K, V> * pCur = ptr;
AVLNode<K, V> * pParent = ptr;
AVLNode<K, V> * gParent = NULL;
AVLNode<K, V> * q; // 左右子树均存在时,找左子树的右结点
stack<AVLNode<K, V> *> s;
int pd = 0;
int gd = 0;
// 找到需要被删除的结点,将路径上的结点记录在栈中
while (pCur != NULL)
{
if (key == pCur->key)
break;
pParent = pCur;
s.push(pParent);
if (key > pCur->key)
pCur = pCur->_pRight;
else
pCur = pCur->_pLeft;
}
if (pCur == NULL)
return false;
if (pCur->_pLeft != NULL && pCur->_pRight != NULL)
{
pParent = pCur;
s.push(pParent);
q = pCur->_pLeft;
while (q->_pRight != NULL)
{
pParent = q;
s.push(pParent);
q = q->_pRight;
}
pCur->key = q->key;
pCur = q;
}
// 被删除结点pCur只有一个子结点
if (pCur->_pLeft != NULL)
q = pCur->_pLeft;
else
q = pCur->_pRight;
if (pParent == NULL)
ptr = q;
else
{
if (pParent->_pLeft = pCur)
pParent->_pLeft = q;
else
pParent->_pRight = q;
// 重新平衡化
while (s.empty() == false)
{
pParent = s.top();
s.pop();
if (pParent->_pLeft = pCur)
pParent->bf++;
else
pParent->bf--;
if (s.empty() == false)
{
gParent = s.top();
gd = (gParent->_pLeft == pParent) ? -1 : 1;
}
else gd = 0;
if (pParent->bf == 1 || pParent->bf == -1)
break;
if (pParent->_pLeft != 0)
{
if (pParent->bf < 0)
{
pd = -1;
pCur = pParent->_pLeft;
}
else
{
pd = 1;
pCur = pParent->_pRight;
}
if (pCur->bf == 0)
{
if (pd == -1)
{
RotateR(pParent);
pParent->bf = 1;
pParent->_pLeft->bf = -1;
}
else
{
RotateL(pParent);
pParent->bf = -1;
pParent->_pRight->bf = 1;
}
break;
}
if (q->bf == pd)
{
if (pd == -1)
RotateR(pParent);
else
RotateL(pParent);
}
else
{
if (pd == -1)
RotateLR(pParent);
else
RotateRL(pParent);
}
if (gd == -1)
gParent->_pLeft = pParent;
else if (gd == 1)
gParent->_pRight = pParent;
}
q = pParent;
}
if (s.empty() == true)
ptr = pParent;
}
delete pCur;
return true;
}
};
int main()
{
AVLTree<int, int> t;
t.Insert(1, 11);
t.Insert(2, 12);
t.Insert(3, 13);
t.Insert(4, 14);
t.showTree();
t.Remove(2);
return 0;
}