当前位置: 首页 > news >正文

数据结构 - AVL树 (Adelson-Velsky and Landis Tree)

目录

  • 一、前言
  • 二、简介
  • 三、左旋与右旋
  • 四、AVL树的调整
    • 1、向AVL树中插入新数据
      • 1)LL型不平衡(右单旋转)
      • 2)RR型不平衡(左单旋转)
      • 3)LR型不平衡(左右双旋转)
      • 4)RL型不平衡(右左双旋转)
  • 五、代码实现

一、前言

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序,二叉搜索树将有可能退化为单支树,此时查找元素相当于在顺序表中查找元素,效率低下,时间复杂度接近O(n)。请添加图片描述
最优情况下,二叉搜索树为完全二叉树。
最差情况下,二叉搜索树退化为单支树。

二、简介

AVL树是一颗自平衡的二叉树,是对BST的改进。每个节点均有一个平衡因子 p p p p = H e i g h t ( T L ) − H e i g h t ( T R ) p=Height(T_L)-Height(T_R) p=Height(TL)Height(TR))。若每个节点的平衡因子的绝对值均小于等于1,则该树是AVL树。维护这种高度平衡所付出的代价也是很大的,故而实际应用并不多,因此更多的地方是用追求局部平衡而不是整体平衡的红黑树。
请添加图片描述

注:

  1. AVL 树它的任何一个节点的左右子树都是 AVL 树。
  2. AVL 树的查找、插入和删除在平均和最坏情况下都是O(logn)。

三、左旋与右旋

根据BTS树(二叉排序树)的性质,可以看出通过左旋和右旋操作后得到的树仍然是BTS树。
请添加图片描述

四、AVL树的调整

1、向AVL树中插入新数据

和BST一样,首先在叶节点插入数据。在 AVL 树中进行插入或删除节点后,可能导致 AVL 树失衡,需要对以插入路径上离插入节点最近的平衡因子绝对值大于1的节点为根的树进行调整。
这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右),RL(右左)。
请添加图片描述

1)LL型不平衡(右单旋转)

在某个子树的左子树的左子树上插入新节点,导致子树根节点的平衡因子由1变为2。
请添加图片描述

2)RR型不平衡(左单旋转)

在某个子树的左子树的左子树上插入新节点,导致子树根节点的平衡因子由-1变为-2。
请添加图片描述

3)LR型不平衡(左右双旋转)

在某个子树的左子树的右子树上插入新节点,导致子树根节点的平衡因子由1变为2。
请添加图片描述
感觉这里最不好理解,举一个较复杂的样例。其根本思想就是Z节点先进行左旋后进行右旋。
原AVL树:
在这里插入图片描述
插入节点11:
在这里插入图片描述
将节点16左旋右旋:
在这里插入图片描述

4)RL型不平衡(右左双旋转)

在某个子树的右子树的左子树上插入新节点,导致子树根节点的平衡因子由1变为2。
请添加图片描述

五、代码实现

#include <iostream>
#include <algorithm>

class AVL_Node
{
public:
    friend class AVL_Tree;
    AVL_Node() : _key(0), _cnt(0), _height(0), _lchild(0), _rchild(0) {}
    AVL_Node(int key) : _key(key), _cnt(0), _height(0), _lchild(0), _rchild(0) {}
    int height(AVL_Node *node)
    {
        if (!node)
            return -1;
        return node->_height;
    }
    void update_height()
    {
        _height = 1 + std::max(height(_lchild), height(_rchild));
    }
    int getBalenceFactor()
    {
        return height(_lchild) - height(_rchild);
    }
    void preorder(AVL_Node *node, std::ostream &os) const
    {
        if (node)
        {
            os << node->_key << " ";
            if (node->_lchild)
                preorder(node->_lchild, os);
            if (node->_rchild)
                preorder(node->_rchild, os);
        }
    }

private:
    int _key;
    int _cnt;
    int _height;
    AVL_Node *_lchild;
    AVL_Node *_rchild;
};

class AVL_Tree
{
public:
    AVL_Tree() : _root(0) {}
    AVL_Tree(AVL_Node *root) : _root(root) {}
    void insert(const int &);
    AVL_Node *insert_key(AVL_Node *node, const int &);
    AVL_Node *rightRotate(AVL_Node *Y)
    {
        /* 树结构示意图:
                Y
               / \
              X   O
             / \
            O   O
        */
        AVL_Node *X = Y->_lchild;
        AVL_Node *tmp = X->_rchild;
        X->_rchild = Y;
        Y->_lchild = tmp;
        Y->update_height();
        X->update_height();
        return X;
    }
    AVL_Node *leftRotate(AVL_Node *Y)
    {
        /* 树结构示意图:
                Y
               / \
              O   X
                 / \
                O   O
        */
        AVL_Node *X = Y->_rchild;
        AVL_Node *tmp = X->_lchild;
        X->_lchild = Y;
        Y->_rchild = tmp;
        Y->update_height();
        X->update_height();
        return X;
    }

    void preOrder();

private:
    AVL_Node *_root;
};

void AVL_Tree::insert(const int &key)
{
    if (!_root)
    {
        _root = new AVL_Node(key);
    }
    else
    {
        _root = insert_key(_root, key);
    }
}

AVL_Node *AVL_Tree::insert_key(AVL_Node *node, const int &key)
{
    if (key == node->_key)
    {
        ++(node->_cnt);
        return node;
    }

    if (key < node->_key)
    {
        if (!node->_lchild)
            node->_lchild = new AVL_Node(key);
        else
            node->_lchild = insert_key(node->_lchild, key);
    }
    else if (key > node->_key)
    {
        if (!node->_rchild)
            node->_rchild = new AVL_Node(key);
        else
            node->_rchild = insert_key(node->_rchild, key);
    }

    // 更新路径上每个节点的高度。
    node->update_height();
    // 计算平衡因子。
    int p = node->getBalenceFactor();

    // LL型不平衡。
    if (p > 1 && key < node->_lchild->_key)
    {
        return rightRotate(node);
    }
    // RR型不平衡。
    if (p < -1 && key > node->_rchild->_key)
    {
        return leftRotate(node);
    }
    // LR型不平衡。
    if (p > 1 && key > node->_lchild->_key)
    {
        node->_lchild = leftRotate(node->_lchild);
        return rightRotate(node);
    }
    // RL型不平衡。
    if (p < -1 && key < node->_rchild->_key)
    {
        node->_rchild = rightRotate(node->_rchild);
        return leftRotate(node);
    }
    return node;
}

void AVL_Tree::preOrder()
{
    std::cout << "preOrder: ";
    if (_root)
        _root->preorder(_root, std::cout);
    std::cout << std::endl;
}

int main()
{
    AVL_Tree* avl = new AVL_Tree();
    avl->insert(10);
    avl->insert(20);
    avl->insert(30);
    avl->insert(40);
    avl->insert(50);
    avl->insert(25);
    
    avl->preOrder();
}

相关文章:

  • 网站建设成本/免费的seo优化
  • 如何做公司培训网站/营销公司网站
  • 赣州推广平台/广州网站优化推广方案
  • 梵讯企业网站建设/海阳seo排名优化培训
  • 自己怎么做卡盟网站/磁力宝最佳搜索引擎入口
  • 网站推广公司兴田德润/cpc广告接单平台
  • 华为OD机试真题 C++ 实现【货币单位换算】【2022.11 Q4 新题】
  • 非零基础自学Golang 第16章 正则表达式 16.3 regexp包 16.4 小结 16.5 知识拓展
  • Linux系统 PHP安装expect扩展详解
  • (二十)Vue之非单文件组件
  • always块中时序逻辑 negedge rst_n和posedge rst实际电路
  • es笔记五之term-level的查询操作
  • 用简单伪随机数发生器实现随机中点位移分形(Matlab代码实现)
  • Macos安装和卸载第三方软件的正确方法
  • 02-Spring Boot启动原理核心源码剖析
  • 数据库实验5 数据库设计实验
  • Opencv(C++)笔记--直方图均衡化、直方图计算
  • spring-statemachine状态机梳理