由于之前的搜索二叉树在单支树的情况下,时间复杂度依然为 O(N),所以我们应该对其进行调整,此时遍出现了 AVL 树,AVL 树是最先发明的自平衡二叉搜索树。在AVL树中,在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是 O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
特点 :
1. AVL树本身依然是搜索二叉树。
2. 每个节点的左右子树高度差的绝对值小于等于1.
插入:
向 AVL 树中插入,首先如同二叉搜索树一样,先找到插入的位置,然后将节点插入。此时插入节点的平衡因子值为 0(因为其左右子树高度差为0),接着自底向上折
回并更新双亲节点的平衡因子(左树-1,右树+1),如果某个节点的平衡因子等于 +2或 -1 时,此时该树是不平衡的,需要对这个树进行平衡调整:
左旋:
右旋:
左右旋:
左右旋特殊场景
右左旋:
右左旋特殊场景
上面的四种算法即是AVL 树的平衡调整算法,经过调整后的 AVL树,高度会控制在 log(N)的范围内,插入和查找的时间复杂度也会控制在 log(N)的范围内。
实现:
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) // key 大于 根节点 key 向右移动
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key) // key 值小于 根节点 key 向左移动
{
parent = cur;
cur = cur->_left;
}
else // 存在相同 key 值
return false;
}
// 插入
cur = new Node(key, value);
if (cur->_key < parent->_key) // 判断插左还是插右
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
//更新平衡因子
while (parent)
{
if (cur == parent->_left) // 左右
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0) //无需调整
break;
else if (parent->_bf == 1 || parent->_bf == -1)
{ // 向上调整
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{ // 失去平衡,进行调整
if (parent->_bf == 2) // 右树失衡
{
if (cur->_bf == 1) // 右树的右树
{
//左单旋
RotateLeft(parent);
}
else // 右树的左树
{ // 右左旋
int inode = cur->_left->_bf; // 特殊场景
RotateRight(cur);
RotateLeft(parent);
if (inode == 1)
parent->_bf = -1;
else if (inode == -1)
cur->_bf = 1;
}
}
if (parent->_bf == -2) // 左树失衡
{
if (cur->_bf == -1)
{ // 左树的左树
// 右单旋
RotateRight(parent);
}
else
{ // 左树的右树
// 左右双旋
int inode = cur->_right->_bf;
RotateLeft(cur);
RotateRight(parent);
if (inode == 1)
cur->_bf = -1;
else if (inode == -1)
parent->_bf = 1;
}
}
return true;
}
}
return true;
}
void RotateLeft(Node* parent) // 左单旋
{
Node * subR = parent->_right;
Node * subRL = subR->_left;
// 旋转
parent->_right = subRL;
if (subRL) // 存在的话
subRL->_parent = parent;
subR->_left = parent;
Node* pParent = parent->_parent;
parent->_parent = subR;
if (pParent == NULL) // 根节点的情况
{
_root = subR;
subR->_parent = NULL;
}
else //不是根节点
{
if (subR->_key < pParent->_key) // 如果在双亲的左侧
{
pParent->_left = subR;
}
else // 在双亲节点的右侧
{
pParent->_right = subR;
}
subR->_parent = pParent;
}
// 更新平衡因子
parent->_bf = subR->_bf = 0;
}
void RotateRight(Node * parent) // 右单旋
{
Node *subL = parent->_left;
Node *subLR = subL->_right;
//旋转
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* pParent = parent->_parent;
parent->_parent = subL;
if (pParent == NULL) //如果是根节点
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (subL->_key < pParent->_key)
pParent->_left = subL;
else
pParent->_right = subL;
subL->_parent = pParent;
}
parent->_bf = subL->_bf = 0;
}
插入完成后,我们需要对整棵树进行判断,判断其是否平衡,为了避免插入时平衡因子的计算错误,所以我们不能根据平衡因子进行判断,而是根据其每个节点的左右子树的高度差来进行判断:
实现:
bool _IsBalance(Node* root)
{
if (abs(Heigh(root->_left) - Heigh(root->_right)) >= 2)
return false;
return true;
}
private:
int Heigh(Node* root)
{
if (root == 0)
return 0;
if (Heigh(root->_left) > Heigh(root->_right))
return 1 + Heigh(root->_left);
else
return 1 + Heigh(root->_right);
}
此时二叉搜索树已经实现了平衡,打完收工。
所有代码:
#pragma once
#include <iostream>
#include <assert.h>
#include <math.h>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode<K, V> *_left;
AVLTreeNode<K, V> *_right;
AVLTreeNode<K, V> *_parent; //父节点
K _key; //键值
V _value;
int _bf; //平衡因子
AVLTreeNode(K key, V value)
:_left(NULL)
,_right(NULL)
,_parent(NULL)
,_key(key)
,_value(value)
,_bf(0)
{}
};
template<class K, class V>
class AVLTree
{
public:
typedef AVLTreeNode<K, V> Node;
AVLTree()
:_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) // key 大于 根节点 key 向右移动
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key) // key 值小于 根节点 key 向左移动
{
parent = cur;
cur = cur->_left;
}
else // 存在相同 key 值
return false;
}
// 插入
cur = new Node(key, value);
if (cur->_key < parent->_key) // 判断插左还是插右
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
//更新平衡因子
while (parent)
{
if (cur == parent->_left) // 左右
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0) //无需调整
break;
else if (parent->_bf == 1 || parent->_bf == -1)
{ // 向上调整
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{ // 失去平衡,进行调整
if (parent->_bf == 2) // 右树失衡
{
if (cur->_bf == 1) // 右树的右树
{
//左单旋
RotateLeft(parent);
}
else // 右树的左树
{ // 右左旋
int inode = cur->_left->_bf; // 特殊场景
RotateRight(cur);
RotateLeft(parent);
if (inode == 1)
parent->_bf = -1;
else if (inode == -1)
cur->_bf = 1;
}
}
if (parent->_bf == -2) // 左树失衡
{
if (cur->_bf == -1)
{ // 左树的左树
// 右单旋
RotateRight(parent);
}
else
{ // 左树的右树
// 左右双旋
int inode = cur->_right->_bf;
RotateLeft(cur);
RotateRight(parent);
if (inode == 1)
cur->_bf = -1;
else if (inode == -1)
parent->_bf = 1;
}
}
return true;
}
}
return true;
}
void RotateLeft(Node* parent) // 左单旋
{
Node * subR = parent->_right;
Node * subRL = subR->_left;
// 旋转
parent->_right = subRL;
if (subRL) // 存在的话
subRL->_parent = parent;
subR->_left = parent;
Node* pParent = parent->_parent;
parent->_parent = subR;
if (pParent == NULL) // 根节点的情况
{
_root = subR;
subR->_parent = NULL;
}
else //不是根节点
{
if (subR->_key < pParent->_key) // 如果在双亲的左侧
{
pParent->_left = subR;
}
else // 在双亲节点的右侧
{
pParent->_right = subR;
}
subR->_parent = pParent;
}
// 更新平衡因子
parent->_bf = subR->_bf = 0;
}
void RotateRight(Node * parent) // 右单旋
{
Node *subL = parent->_left;
Node *subLR = subL->_right;
//旋转
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* pParent = parent->_parent;
parent->_parent = subL;
if (pParent == NULL) //如果是根节点
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (subL->_key < pParent->_key)
pParent->_left = subL;
else
pParent->_right = subL;
subL->_parent = pParent;
}
parent->_bf = subL->_bf = 0;
}
bool IsBalance()//判断是否平衡
{
return _IsBalance(_root);
}
void InOrder()
{
_Inorede(_root);
}
private:
void _Inorede(Node* root)
{
if (root == NULL)
return;
_Inorede(root->_left);
printf("%d\n", root->_value);
_Inorede(root->_right);
}
bool _IsBalance(Node* root)
{
if (abs(Heigh(root->_left) - Heigh(root->_right)) >= 2)
return false;
return true;
}
private:
int Heigh(Node* root)
{
if (root == 0)
return 0;
if (Heigh(root->_left) > Heigh(root->_right))
return 1 + Heigh(root->_left);
else
return 1 + Heigh(root->_right);
}
Node *_root;
};
void test()
{
AVLTree<int, int> t;
int array[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (int i = 0; i < sizeof(array) / sizeof(int); i++)
t.Insert(array[i],array[i]);
if (t.IsBalance())
cout << "平衡" << endl;
else
cout << "不平衡" << endl;
t.InOrder();
}