如果二叉搜索树的插入序列是有序的或者是接近有序,那么二叉搜索树就会退化为单支树(类似单链表),查找元素相当于在顺序表中搜索元素,时间复杂度为O(N)。
AVLtree(Adelson Velskii Landis tree)是一个加上额外平衡条件的二叉搜索树,左右子树高度之差(简称平衡因子)的绝对值不超过1,如果它有n个节点,高度可保持在O(logn),搜索时间复杂度为O(logn)。
template <class K, class V>
struct 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)
{
}
};
AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么AVL树的插入过程可以分为两步:
1.按照二叉搜索树的方式插入新节点
2.插入后调整节点的平衡因子
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;//此时parent->bf=-2,左边高
Node* subLR = subL->_right;
//将subLR链接到parent的左侧
parent->_left = subLR;
if (subLR != nullptr)
{
subLR->_parent = parent;//修改自己的parent
}
Node* pParent = parent->_parent;//保存一份
//将parent连接到subL的右侧
subL->_right = parent;
parent->_parent = subL;
//将subL与pParent链接起来
if (pParent == nullptr)
{
_root = subL;//subL变成新的根
subL->_parent = nullptr;
}
else//不为根
{
if (pParent->_left == parent)//parent在上一层的左侧
{
pParent->_left = subL;
}
else
{
pParent->_right = subL;
}
subL->_parent = pParent;
}
//平衡因子的更新
parent->_bf = 0;
subL->_bf = 0;
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
//subRL连接到parent
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;//NULL BUg
Node* pParent = parent->_parent;//保存一份来连接
//parent连接到subR上面
subR->_left = parent;
parent->_parent = subR;
if (pParent == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else // 不为根
{
if (pParent->_left == parent)//parent在上一层的左侧
{
pParent->_left = subR;
}
else
{
pParent->_right = subR;
}
subR->_parent = pParent;
}
//平衡因子更新
parent->_bf = subR->_bf = 0;
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = parent->_left->_right;
int bf = subLR->_bf;
RotateL(subL);//先左旋
RotateR(parent);//再右旋
if (bf == 1)//说明是subLR是右树插入
{
subLR->_bf = 0;
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)//说明是subLR是左树插入
{
subLR->_bf = 0;
parent->_bf = 1;
subL->_bf = 0;
}
else if (bf == 0)
{
subLR->_bf = subL->_bf = parent->_bf = 0;
}
else
{
assert(false);
}
}
新节点插入较高右子树的左侧—右左:先右单旋再左单旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);//先右旋
RotateL(parent);//再左旋
if (bf == 1)//在subRL右侧插入时
{
subRL->_bf = 0;
parent->_bf = -1;
subR->_bf = 0;
}
else if (bf == -1)//在左侧插入时
{
subRL->_bf = 0;
parent->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
subRL->_bf = subR->_bf = parent->_bf = 0;
}
else
{
assert(false);
}
}
总结:
假如以Parent为根的子树不平衡,即Parent的平衡因子为2或者-2,分以下情况考虑
旋转完成后,原Parent为根的子树个高度降低,已经平衡,不需要再向上更新。
#pragma once
#include
#include
#include
#include
using namespace std;
template <class K, class V>
struct 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)
{
}
};
template<class K, class V>
struct AVLTree
{
typedef struct AVLTreeNode<K, V> Node;
public:
AVLTree() = default;
AVLTree(const AVLTree<K, V>& t);
AVLTree<K, V>& operator=(AVLTree<K, V> t);
//~AVLTree();
//插入节点
pair<Node*, bool> Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return make_pair(_root, true);
}
//有根了,按照平衡二叉树的方法进行插入
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)//K值比较,小于往左边走
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(cur, false);//相等,返回已有元素的指针
}
}
//找到插入的位置了,判断插入左边还是右边
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//1.更新平衡因子
//新增节点会影响它到这条节点路径上的祖先
Node* newNode = cur;//提前保存cur
while (parent)
{
if (cur == parent->_right)//cur在parent左侧
{
parent->_bf++;
}
else//cur在parent的右侧
{
parent->_bf--;
}
if (parent->_bf == 0)//调节后parent的_bf为0,说明这棵树已经平衡
{
break;
}
else if(abs(parent->_bf) == 1)//继续往上走
{
cur = parent;
parent = parent->_parent;
}
else if (abs(parent->_bf) == 2)//不平衡了 旋转
{
if (parent->_bf == -2)
{
if (cur->_bf == -1)//右旋
{
RotateR(parent);
}
else // cur->_bf == 1
{
RotateLR(parent);
}
}
else // parent->_bf == 2
{
if (cur->_bf == 1)
{
RotateL(parent);//左旋
}
else // cur->_bf == -1
{
RotateRL(parent);
}
}
break;
}
else
{
assert(false);//不可能走到这一步,走到这里说明发生了逻辑错误
}
}
return make_pair(newNode, true);
}
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;//此时parent->bf=-2,左边高
Node* subLR = subL->_right;
//将subLR链接到parent的左侧
parent->_left = subLR;
if (subLR != nullptr)
{
subLR->_parent = parent;//修改自己的parent
}
Node* pParent = parent->_parent;//保存一份
//将parent连接到subL的右侧
subL->_right = parent;
parent->_parent = subL;
//将subL与pParent链接起来
if (pParent == nullptr)
{
_root = subL;//subL变成新的根
subL->_parent = nullptr;
}
else//不为根
{
if (pParent->_left == parent)//parent在上一层的左侧
{
pParent->_left = subL;
}
else
{
pParent->_right = subL;
}
subL->_parent = pParent;
}
//平衡因子的更新
parent->_bf = 0;
subL->_bf = 0;
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
//subRL连接到parent
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;//NULL BUg
Node* pParent = parent->_parent;//保存一份来连接
//parent连接到subR上面
subR->_left = parent;
parent->_parent = subR;
if (pParent == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else // 不为根
{
if (pParent->_left == parent)//parent在上一层的左侧
{
pParent->_left = subR;
}
else
{
pParent->_right = subR;
}
subR->_parent = pParent;
}
//平衡因子更新
parent->_bf = subR->_bf = 0;
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = parent->_left->_right;
int bf = subLR->_bf;
RotateL(subL);//先左旋
RotateR(parent);//再右旋
if (bf == 1)//说明是subLR是右树插入
{
subLR->_bf = 0;
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)//说明是subLR是左树插入
{
subLR->_bf = 0;
parent->_bf = 1;
subL->_bf = 0;
}
else if (bf == 0)
{
subLR->_bf = subL->_bf = parent->_bf = 0;
}
else
{
assert(false);
}
}
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);//先右旋
RotateL(parent);//再左旋
if (bf == 1)//在subRL右侧插入时
{
subRL->_bf = 0;
parent->_bf = -1;
subR->_bf = 0;
}
else if (bf == -1)//在左侧插入时
{
subRL->_bf = 0;
parent->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
subRL->_bf = subR->_bf = parent->_bf = 0;
}
else
{
assert(false);
}
}
int Height(Node* root)
{
if (root == NULL)
{
return 0;
}
return max(Height(root->_left), Height(root->_right)) + 1;
}
bool _IsBalance(Node* root)
{
if (root == NULL)
{
return true;
}
int leftHeight = Height(root->_left);
int rightHeight = Height(root->_right);
if (rightHeight - leftHeight != root->_bf)
{
cout << "平衡因子异常:" << root->_kv.first << endl;
}
return abs(leftHeight - rightHeight) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right);
}
bool IsBalance()
{
return _IsBalance(_root);
}
//遍历的时候 root为private外面无法拿到
//因此需要封装一层
void _Inorder(Node* root)
{
if (root == nullptr)
return;
_Inorder(root->_left);
cout << root->_kv.first << " " ;
_Inorder(root->_right);
}
//遍历
void Inorder()
{
_Inorder(_root);
cout << endl;
}
Node* Find(const K& key);
V& operator [] (const K& k);//string、int、vector等等都可以是V,是由默认的构造函数的 int()=0
private:
Node* _root = nullptr;
};
void TestAVLTree()
{
int a[] = {
16, 3, 7, 11, 9, 26, 18, 14, 15 };
//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
AVLTree<int, int> t;
for (auto& e : a)
{
t.Insert(make_pair(e, e));
}
t.Inorder();
cout << t.IsBalance() << endl;
}