前言:
什么叫做AVL树?
AVL树的定义:
1、AVL的左右子树高度之差的绝对值不超过1;
2、树中的左右子树都为AVL树
3、平衡因子只能是(-1、0、1)
AVL树的效率
AVL树的总共节点为N个,他的高度能搞保持在logN,插入、删除、查找等操作的时间复杂度也是logN。
AVL树的实现:
1、AVL树的插入:
思路分析:1> 既然是插入就需要先找到插入的位置,使用while循环遍历找到插入位置
2> 找到插入位置以后直接插入,然后向上遍历修改父节点的平衡因子,当修改完以后的平衡因子有等于2或者-2的挑出来,进行树的旋转,并且调整平衡因子,使满足AVL树的定义。
3> 旋转过程中需要考虑是左旋转、右旋转、左右旋转、还是右左旋转。左右旋转简单,直接调用自己编写的左右旋转函数即可,只要传过来的节点记得加上引用就行了,这样能够直接连接到旋转后的子树。重点在于左右和右左旋转,我们是否能直接调用左旋转函数和右旋转函数各一次?答案是否定的,因为在旋转的过程中,不是在插入的那个位置进行旋转,而是在中间进行旋转,这是后父亲节点和祖父节点的平衡因子BF就需要自己手动来定义了。以右左旋转来分析:
如果当前节点的平衡因子为-1,那么他的parent应该为1,pparent应该为0;
如果当前节点的平衡因子为1,那么他的parent应该为0,pparent应该为-1;
如果当前节点的平衡因子为0,那么他的parent应该为0,pparent应该为0;
具体自己下去画个图,在插入节点的位置(cur)下面加一个左节点或者右节点,然后分析。
#ifndef __BALANCETREE_H__
#define __BALANCETREE_H__
template<class K,class V>
struct BLNode
{
K _key;
V _value;
BLNode<K, V>* _left;
BLNode<K, V>* _right;
BLNode<K, V>* _parent;
int _bf;
BLNode(const K& key, const V& value)
:_key(key)
, _value(value)
, _parent(NULL)
, _left(NULL)
, _right(NULL)
, _bf(0)
{}
};
template<class K,class V>
class BalanceTree
{
typedef BLNode<K, V> Node;
public:
BalanceTree()
:_root(NULL)
{}
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 (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//找到插入位置以后,确定平衡因子
Node* ppNode = parent->_parent;
if (parent->_key > key)//找到插入位置以后判断是在父节点的左边还是右边,插入以后先调整平衡因子,向上遍历,如果本来是-1或者1插入以后为0就不用调整了,因为上一层看到的还是这一层的高度没有变
{
cur = new Node(key, value);
parent->_left = cur;
cur->_parent = parent;
parent->_bf--;
while (parent)
{
if ((parent->_bf == -1 ||parent->_bf ==1)&& parent->_parent != NULL)
{
if (parent->_parent->_key >parent->_key)
parent->_parent->_bf--;
else if (parent->_parent->_key < parent->_key)
parent->_parent->_bf++;
if (parent->_parent->_bf == 2 || parent->_parent->_bf == -2)
break;
cur = parent;
parent = parent->_parent;
}
else
break;
}
}
else if (parent->_key < key)
{
cur = new Node(key, value);
parent->_right = cur;
cur->_parent = parent;
parent->_bf++;
while (parent)
{
if ((parent->_bf == 1 ||parent->_bf == -1)&& parent->_parent != NULL)
{
if (parent->_parent->_key >parent->_key)
parent->_parent->_bf--;
else if (parent->_parent->_key < parent->_key)
parent->_parent->_bf++;
if (parent->_parent->_bf == 2 || parent->_parent->_bf == -2)
break;
cur = parent;
parent = parent->_parent;
}
else
break;
}
}
//根据平衡因子的变动,开始调整当前的树,因为刚刚是平衡因子不符合的时候跳出来的
ppNode = parent->_parent;
Node* pppNode = NULL;
if (ppNode!=NULL)
pppNode = ppNode->_parent;
if (ppNode && (ppNode->_bf == 2 || ppNode->_bf == -2))
{
//左旋
if (parent == ppNode->_right && parent->_right == cur)
{
RotateL(ppNode);
}
//右旋
else if (ppNode->_left == parent && parent->_left == cur)
{
RotateR(ppNode);
}
//左右双旋
else if (ppNode->_left == parent &&parent->_right == cur)
{
int bf = cur->_bf;
Node* pNode = ppNode;
Node* pLeftNode = parent;
RotateL(parent);//先左旋,再链接
ppNode->_left = parent;
RotateR(ppNode);
if (bf == 0)
{
pNode->_bf = 0;
pLeftNode->_bf = 0;
}
else if (bf == -1)
{
pNode->_bf = 1;
pLeftNode->_bf = 0;
}
else if (bf == 1)
{
pNode->_bf = 0;
pLeftNode->_bf = -1;
}
}
//右左双旋
else if (ppNode->_right == parent &&parent->_left == cur)
{
int bf = cur->_bf;
Node* pNode = ppNode;
Node* pRightNode = parent;
RotateR(parent);
ppNode->_right = parent;
RotateL(ppNode);
if (bf == 0)
{
pNode->_bf = 0;
pRightNode->_bf = 0;
}
else if (bf == -1)
{
pNode->_bf = 0;
pRightNode->_bf = 1;
}
else if (bf == 1)
{
pNode->_bf = -1;
pRightNode->_bf = 0;
}
}
if (pppNode == NULL)
{
_root = ppNode;
}
else
{
if (pppNode->_key > ppNode->_key)
pppNode->_left = ppNode;
else if (pppNode->_key < ppNode->_key)
pppNode->_right = ppNode;
}
}
}
size_t Height()
{
return _Height(_root);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
protected:
size_t _Height(Node* root)
{
if (root == NULL)
return 0;
return _Height(root->_left) > _Height(root->_right) ? _Height(root->_left) + 1 : _Height(root->_right) + 1;
}
void _InOrder(Node* root)
{
if (root == NULL)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
void rotateL(Node*& parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_parent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
parent->_right = subRL;
if (subRL != NULL)
subRL->_parent = parent;
parent->_bf = 0;
subR->_bf = 0;
parent = subR;
}
void RotateL(Node*& parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL != NULL)
subRL->_parent = parent;
subR->_parent = parent->_parent;
parent->_parent = subR;
subR->_left = parent;
parent->_bf = 0;
subR->_bf = 0;
parent = subR;
}
void RotateR(Node*& parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR != NULL)
subLR->_parent = parent;
subL->_parent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
parent->_bf = 0;
subL->_bf = 0;
parent = subL;
}
protected:
Node* _root;
};
void test()
{
BalanceTree<int, int> bt;
int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
bt.Insert(arr[i], i);
}
bt.InOrder();
cout << bt.Height() << endl;
BalanceTree<int, int> bt1;
int arr1[] = { 4,2,6,1,3,5,15,7,16,14 };
for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
{
bt1.Insert(arr1[i], i);
}
bt1.InOrder();
cout << bt1.Height() << endl;
}
#endif //__BALANCETREE_H__
2、AVL树的删除:
删除相对而言跟插入差不多,都是需要理解过程的,对于删除,我们只需要先找到要删除的位置,然后分为三种情况:
1.左为空-------->直接连接到父节点上,只是需要判断连接到父节点的左还是右上
2.右为空-------->同上
3.左右都不为空:找到右边子树的最左节点,(这里还分为两种情况:没有左子节点和有)这里只分析有左子节点的了,一直往左遍历找到左子节点,交换左子节点和要删除的节点,然后将parent->left连到左子节点的右就行了,最后一步就是调节平衡因子了,从当前节点开始向上修改平衡因子,以及判断平衡因子有没有为2或者-2的情况,然后跟上面一样做处理。
来源:CSDN
作者:zangyuanan320
链接:https://blog.csdn.net/zangyuanan320/article/details/52077905