树和节点的定义
template<class K,class V>
class AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
int _bf;
AVLTreeNode(const pair<K,V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_bf(0)
{}
};
插入
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
//父链接子,子要反向链接父
cur->_parent = parent;
//update bf
while (parent)
{
if (cur == parent->_right)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if (parent->_bf == 1 || parent->_bf == -1)
{
parent = parent->_parent;
cur = cur->_parent;
}
else if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//rotate
}
else
{
assert(false);
}
}
return true;
}
平衡因子的调整
1.parent->bf等于1||-1,说明parent所在的子树高度变了,(因为插入前parent->bf等于0,插入前左右子树高度相等,现在有一边高了)需要继续向上更新平衡因子。
2.parent->bf等于2||-2,parent所在的子树不平衡,需要旋转处理这棵子树。
3.parent->bf等于0,parent所在的子树平衡无需更新。
旋转
我们先定义有以上三种子节点,分别记为x,y,z,以便后文讲解。
左单旋
上述这种情况,c只能是x,若非那么c节点本身就要先旋转调整。
b变成了30的右边,30变成60的左边,60变成整棵树的根。
注意点:1.双向连接2.subRL可能为空3.parent是否为根
代码实现:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
//判断上面是否有根
if (ppNode == nullptr)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subR;
subR->_parent = ppNode;
}
else
{
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
parent->_bf = subR->_bf = 0;
}
右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppNode = parent->_parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (ppNode == nullptr)
{
_root = subL;
_root->_parent = nullptr;
}
else if(ppNode->_left==parent)
{
ppNode->_left = subL;
subL->_parent = ppNode;
}
else
{
ppNode->_right = subL;
subL->_parent = ppNode;
}
parent->_bf = subL->_bf = 0;
}
左右双旋
难点:平衡因子的调整
以上图为例,记录subLR初始的bf,然后分三种情况讨论即可
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 1)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
}
右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
RotateL(parent);
if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 0;
}
else
assert(false);
}
判断是否为平衡二叉树
bool IsBalance()
{
return _IsBalance(_root);
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
return true;
int lefth = _Height(root->_left);
int righth = _Height(root->_right);
if (righth - lefth != root->_bf)
{
cout << root->_kv.first << "节点平衡因子异常" << endl;
}
return abs(lefth - righth) < 2 && _IsBalance(root->_left)&&_IsBalance(root->_right);
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftH = _Height(root->_left);
int rightH = _Height(root->_right);
return (leftH > rightH ? leftH : rightH) + 1;
}
注意这里我们用递归获得子树的高度后,判断左右子树绝对值是否小于2还不行,还要逐层递归下去判断子树。
完整代码
#pragma once
#include<assert.h>
#include<iostream>
#include<time.h>
using namespace std;
template<class K,class V>
class AVLTreeNode
{
public:
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
int _bf;
AVLTreeNode(const pair<K,V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_bf(0)
{}
};
template<class K,class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
//父链接子,子要反向链接父
cur->_parent = parent;
//update bf
while (parent)
{
if (cur == parent->_right)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if (parent->_bf == 1 || parent->_bf == -1)
{
parent = parent->_parent;
cur = cur->_parent;
}
else if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//rotate
if (parent->_bf == 2 && cur->_bf == 1)
RotateL(parent);
else if (parent->_bf == -2 && cur->_bf == -1)
RotateR(parent);
else if (parent->_bf == -2 && cur->_bf == 1)
RotateLR(parent);
else if (parent->_bf == 2 && cur->_bf == -1)
RotateRL(parent);
else
assert(false);
break;
}
else
{
assert(false);
}
}
return true;
}
private:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
//判断上面是否有根
if (ppNode == nullptr)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subR;
subR->_parent = ppNode;
}
else
{
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
parent->_bf = subR->_bf = 0;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppNode = parent->_parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (ppNode == nullptr)
{
_root = subL;
_root->_parent = nullptr;
}
else if(ppNode->_left==parent)
{
ppNode->_left = subL;
subL->_parent = ppNode;
}
else
{
ppNode->_right = subL;
subL->_parent = ppNode;
}
parent->_bf = subL->_bf = 0;
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 1)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
}
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
RotateL(parent);
if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 0;
}
else
assert(false);
}
public:
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
return _IsBalance(_root);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << " ";
_InOrder(root->_right);
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
return true;
int lefth = _Height(root->_left);
int righth = _Height(root->_right);
if (righth - lefth != root->_bf)
{
cout << root->_kv.first << "节点平衡因子异常" << endl;
}
return abs(lefth - righth) < 2 && _IsBalance(root->_left)&&_IsBalance(root->_right);
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftH = _Height(root->_left);
int rightH = _Height(root->_right);
return (leftH > rightH ? leftH : rightH) + 1;
}
private:
Node* _root=nullptr;
};
void Test_AVLTree1()
{
int a[] = { 16,3,7,11,9,26,18,14,15 };
AVLTree<int, int> t1;
for (int e : a)
{
t1.Insert(make_pair(e,e));
}
t1.InOrder();
cout<<t1.IsBalance();
}
//生成随机数测试
void Test_AVLTree2()
{
srand(time(0));
const size_t N = 10000;
AVLTree<int, int> t;
for (size_t i = 0; i < N; i++)
{
size_t x = rand();
t.Insert(make_pair(x, x));
//cout << t.IsBalance() << endl;
}
cout << t.IsBalance() << endl;
}