AVL树旋转原理和简易实现
二叉搜索树虽然可以提高搜索效率,但是如果插入的数据有序时很有可能变成单支,如果变成单支树的时候,那么查找时效率也不高了。因此引入AVL树。
AVL树是当向这棵树插入节点的时候,要保证每个节点的左右子树的高度差都不超过1,如果超过1时就要对这棵树的分支进行旋转。
AVL树的特性:
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
这棵树就是一颗AVL树,它的每个节点的平衡因子的节点的绝对值都不超过1。
AVL树节点的定义
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;//指向左
AVLTreeNode<K, V>* _right;//指向右
AVLTreeNode<K, V>* _parent;//指向父亲
std::pair<K, V> _kv;
int _bf;//平衡因子
};
AVL树的插入
AVL树的插入需要以下几步:
- 如果是空树,那么直接让root等于这个新开节点,并把平衡因子设置为0
- 如果不是空树,那么我们就去找插入的位置,比该值小去左边找,比该值大去右边找
- 找到之后我们新开一个节点,然后将这个节点连接到这个树中
- 最后也是最重要的一步:更新平衡因子。
前三步和二叉搜索树是一样的,但是因为AVL树是一个绝对平衡的树,因此插入之后需要更新平衡因子,(如果在该节点的左边插入那么平衡因子- -,如果在该节点的右边插入那么平衡因子+ +)如果说平衡因子的绝对值大于1,那就说明这棵树的左右高度差已经超过1了,因此需要对这个支进行旋转。
旋转又分为以下几种情况:
情况一:新节点插入较高左子树的左侧(右单旋)
当插入节点之后,60的平衡因子会变成-2,需要进行调整。如果b存在,那么让b变成60的左子树,让60变成30的右子树,30变为根节点。整个旋转过程结束后,30的平衡因子变成0,满足AVL树的条件。
可以这么旋转的原因是,30的右子树b如果存在则一定比30大,但是比60小,因此这个b一定可以去做60的左子树。
旋转方法
void RotateR(Node* parent)//右单旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* ppnode = parent->_parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
}
else
{
if (ppnode->_left == parent)
ppnode->_left = subL;
else
ppnode->_right = subL;
}
subL->_parent = ppnode;
subL->_bf = parent->_bf = 0;
}
情况二: 新节点插入较高右子树的右侧(左单旋)
插入节点后,30的平衡因子变为2,需要进行旋转,让b变为30的右子树,让30变为60的左子树,60变为根节点。整个旋转过程结束后,60的平衡因子变成0,满足AVL树的条件。
可以这么旋转的原因是60的左子树b一定比60小,但是一定比30大,因此可以去做30的右子树。
旋转方法
void RotateL(Node* parent)//左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
}
else
{
if (ppnode->_left == parent)
ppnode->_left = subR;
else
ppnode->_right = subR;
}
subR->_parent = ppnode;
subR->_bf = parent->_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)
{
subL->_bf = -1;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 0)
{
subL->_bf = parent->_bf = 0;
}
}
情况四:新节点插入较高右子树的左侧(右左双旋)
void RotateRL(Node* parent)//右左双旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
subRL->_bf = 0;
if (bf == 1)
{
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
subR->_bf = parent->_bf = 0;
}
}
AVL树的判断平衡
判断平衡我们可以采用递归的方法,就是去判断每一个节点的左右子树是不是平衡的(左右子树的高度差不超过1)。
既然要求高度差,那么我们就要写一个求高度的函数Height
,然后再写一个IsBalance
判断平衡,这里要注意的是必须要递归左子树和右子树,因为必须保证每一颗子树都是平衡的。
int Height(Node* root)//求AVL树的高度
{
if (root == nullptr)
return 0;
int LeftHeight = Height(root->_left);
int RightHeight = Height(root->_right);
return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}
bool IsBalance()
{
return _IsBalance(_root);
}
bool _IsBalance(Node *root)//看每一个节点的左右子树高度差是否不超过1
{
if (root == nullptr)
return true;
int LeftHeight = Height(root->_left);
int RightHeight = Height(root->_right);
//每棵子树的都应该是平衡的(所以需要递归左子树和右子树)
return abs(LeftHeight - RightHeight) < 2
&& _IsBalance(root->_left)
&& _IsBalance(root->_right);
}
AVL树的中序遍历
void Inorder()
{
_Inorder(_root);
cout << endl;
}
void _Inorder(Node* root)//中序遍历
{
if (root == nullptr)
return;
_Inorder(root->_left);
cout << root->_kv.first << " ";
_Inorder(root->_right);
}
完整代码如下
AVLTree.h
#pragma once
#include <iostream>
#include <assert.h>
using std::cout;
using std::endl;
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
std::pair<K, V> _kv;
int _bf;//平衡因子
AVLTreeNode(std::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:
AVLTree()
: _root(nullptr)
{}
bool Insert(std::pair<K, V> &kv)
{
//空树的情况
if (_root == nullptr)
{
_root = new Node(kv);
_root->_bf = 0;
return 0;
}
//不为空树
Node* parent = nullptr;
Node* cur = _root;
while (cur)//找到插入的位置
{
if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(kv);//新开一个节点
//连接起来
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
cur->_parent = parent;
}
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 (abs(parent->_bf) == 1)//继续更新,向上走
{
cur = parent;
parent = parent->_parent;
}
else if (abs(parent->_bf) == 2)
{
//旋转
if (parent->_bf == 2)
{
if (cur->_bf == 1)
{
RotateL(parent);
}
else if (cur->_bf == -1)
{
RotateRL(parent);
}
}
else if (parent->_bf == -2)
{
if (cur->_bf == -1)
{
RotateR(parent);
}
else if (cur->_bf == 1)
{
RotateLR(parent);
}
}
else
{
assert(false);
}
break;
}
else
{
//抛异常
assert(false);
}
}
return true;
}
void RotateL(Node* parent)//左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
}
else
{
if (ppnode->_left == parent)
ppnode->_left = subR;
else
ppnode->_right = subR;
}
subR->_parent = ppnode;
subR->_bf = parent->_bf = 0;
}
void RotateR(Node* parent)//右单旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* ppnode = parent->_parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
}
else
{
if (ppnode->_left == parent)
ppnode->_left = subL;
else
ppnode->_right = subL;
}
subL->_parent = ppnode;
subL->_bf = parent->_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)
{
subL->_bf = -1;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 0)
{
subL->_bf = parent->_bf = 0;
}
}
void RotateRL(Node* parent)//右左双旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
subRL->_bf = 0;
if (bf == 1)
{
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
subR->_bf = parent->_bf = 0;
}
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int LeftHeight = Height(root->_left);
int RightHeight = Height(root->_right);
return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}
bool IsBalance()
{
return _IsBalance(_root);
}
bool _IsBalance(Node *root)
{
if (root == nullptr)
return true;
int LeftHeight = Height(root->_left);
int RightHeight = Height(root->_right);
//每棵子树的都应该是平衡的(所以需要递归左子树和右子树)
return abs(LeftHeight - RightHeight) < 2
&& _IsBalance(root->_left)
&& _IsBalance(root->_right);
}
void Inorder()
{
_Inorder(_root);
cout << endl;
}
void _Inorder(Node* root)
{
if (root == nullptr)
return;
_Inorder(root->_left);
cout << root->_kv.first << " ";
_Inorder(root->_right);
}
private:
Node* _root;
};
void TestAVLTree()
{
AVLTree<int, int> t;
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (auto e : a)
{
t.Insert(std::make_pair(e, e));
}
t.Inorder();
cout << t.IsBalance() << endl;
}
Test.cpp
#include "AVLTree.h"
int main()
{
TestAVLTree();
system("pause");
return 0;
}