AVL树的概念
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当
于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年
发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之 差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。 一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在,搜索时
间复杂度O(log2N)
AVL树平衡因子的更新
- AVL树就是在二叉搜索树的基础上引入了平衡因子
- 具体情况分以下几种情况:
向上更新的过程中,cur也有可能是高度变换子树的根
1,新增节点结点在parent的右边
cur=parent->right
parent->bf++;
2,新增节点结点在parent的左边
cur=parent->left
parent->bf–;
3、更新parent的平衡因子
-
parent->bf=0,说明prent所在子树的高度不变(没更新前parent->bf为1或-1现在变成了0,现在变成了0,说明把缺的那一边填上了不会对上层影响,更新结束,插入结束)
-
parent->bf==1或-1, 说明parent所在子树的高度变了对上一层有影响继续向上更新
- parrent-> bf==2||-2, 说明parent所在子树已经不平衡,要及时旋转
AVL树的插入
AVL树的旋转
AVL的旋转采用抽象图演示:
抽象图->无数多种情况都用旋转处理
1,abc三棵没有具有画出来的树的特点:
a、它们肯定都是高度平衡树
b、他们的高度都是h(h>=0)
当h=0
在30的左右子树插入节点时都会旋转
当h=1
当h=2就会有27中情况
h=3,h=4…可以看出组合的情况更多,但是我们实际不关心,因为a,b,c三棵子树高度多少形态如何,我们的旋转处理都是一样的。
- 右单旋
b成了60的左子树
60成了30的右子树
30成了这棵树根
- 左单旋
b成了30的右子树
30成了60的左子树
60成了这棵树根
- 先左旋在右旋
如果在b插入节点或c插入,导致b或者c的高度变成1,就会引发双旋,并且要分开讨论,b插入或者c插入,树的平衡因子更新是要分开看待的
- 先左旋在右旋
新节点插入较高右子树的左侧—右左:先右单旋再左单旋
代码
初版
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
template<class K, class V>
struct TreeNode {
TreeNode<K, V>* left;
TreeNode<K, V>* right;
TreeNode<K, V>* parent;
pair<K, V> kv;
int bf;//平衡因子
TreeNode(const pair<K, V>& kv)
:left(nullptr),
right(nullptr),
parent(nullptr),
kv(kv),
df(0) {
}
};
template<class K, class V>
class AVLtree {
typedef TreeNode<K, V> Node;
private:
Node * root=nullptr;
public:
AVLtree() = default;
AVLtree(const TreeNode<K, V>& k);
pair<Node*, bool> Insert(cosnt pair<K,V>&kv) {
if (root == nullptr) {
Node cur = new Node(kv);
return make_pair(root, true);
}
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 make_pair(cur, false);
}
}
Node *node = new Node(kv);
if (_parent->kv.first>kv.first) {
_parent->left = kv;
cur->parent = _parent;
}
else {
_parent->right = kv;
cur->parent = _parent;
}
while (_parent) {
if (cur == _parent->left) {
_parent->bf--;
}
else if (cur == _parent->right) {
_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)//是在当前节点的左侧插入了节点 ->右单旋
{
Avr(_parent);
}
else//cur->_bf=1 ->曲线影响
{
Avlr(_parent);
}
}
else//右边高
{
if (cur->_bf == 1)//在当前节点的右侧插入了节点 -> 左单旋
{
Avl(_parent);
}
else//cur->_bf=-1 曲线影响
{
Avl(_parent);
}
}
break;//旋转过后当前的树就是平衡的了,立即退出
}
else {
assert(false);
}
}
//1.更新平衡因子
//新增节点会影响他的到根节点这条路径的祖先
return make_pair(node, true);
}
void Avl(Node *parent) {
Node* subL = parent->left;
Node* subLR = subL->right;
parent->left = subLR;
if (subLR) {
subLR->parent = parent;
}
Node *ne =parent->parent//保存parent的parent
subL->right = parent;
parent->parent = subL;
//parent 是原来的跟
if (parent == root) {
root = parent;
parent->parent = nullptr; //把新树的parent置为空
}
//parent 是原来的子树的根
else {
if (ne->left == parent) {
ne->left = subL;
subL->parent = parent;
}
else {
ne->right = subL;
subL->parent = parent;
}
}
subL->bf = parent->bf = 0;
}
void Avr(Node *parent){
Node* subL = parent->_left;//此时p->bf=-2,左边肯定不为空
Node* subLR = subL->_right;
Node* pparent = parent->_parent;//保存一份
//将子树链接到parent的左侧
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
//将parent连接到subL的右侧
subL->_right = parent;
parent->_parent = subL;
//将subL与ppretn链接起来
if (pparent == nullptr)//subL变成新的根
{
_root = subL;
subL->_parent = nullptr;
}
else//不为根
{
subL->_parent = pparent;
if (parent == pparent->_left)//在上一级节点的左侧
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
}
//平衡因子的更新
parent->_bf = 0;
subL->_bf = 0;
}
void AvLR(Node* parent) {
Node* subL = parent->left;
Node* subLR= parent->left->right;
int bf = parent->bf;
Avl(parent->left);
Avr(parent);
if (bf == 1) {
// 说明subL的右数插入
subL->bf = -1;
subLR->bf = 0;
parent->bf = 0;
}
else if (bf==-1) {//说明subL的左数插入
subL->bf = 0;
subLR->bf = 0;
parent->bf = 1;
}
else if (bf == 0) {//说明SUBLR是新增节点
subL->bf = subLR->bf = parent->bf = 0;
}
}
void AvRL(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//bf==0,新增的
{
subRL->_bf = parent->_bf = subR->_bf = 0;
}
}
bool _isBlace(Node* root) {
if (root == NULL) {
return true;
}
int lheight = Height(root->left);
int rheight = Height(root->left);
if (rheight - lheight != root->bf) {
cout << "平衡因子出错" << root->kv.first << endl;
}
return abc(lheight - rheight) > 2 && _isBlace(root->left) && _isBlace(root->right);
}
//验证是否平衡
bool isBalance() {
_isBalace(root)
}
};