AVL树(Adelson-Velsky and Landis Tree)

AVL树(Adelson-Velsky and Landis Tree)

1.前言

  • 本文中,我们使用KV实现的AVL树。
  • 源码链接放在文章结尾

AVL树Adelson-Velsky and Landis Tree)是一种自平衡的二叉搜索树(BST),它基于二叉搜索树并通过平衡而得到。

AVL树的增删查改都是基于二叉搜索树的,如果不了解二叉搜索树,点我进入二叉搜索树的世界

  • 在前面的学习中我们提到,二叉搜索树可以提高搜索数据的效率,但在数据有序的情况下会退化为单支树,此时在树中查找元素就得遍历一整个分支,时间复杂度也会退化至O(N)。
  • 如果有一种算法,可以使二叉搜索树时刻保持左右子树的平衡,就可以避免这种最坏情况。
  • 两位俄罗斯的数学家G.M.Adelson-VelskiiE.M.Landis在1962年发明了并以他们的名字命名了AVL树,解决了上述问题。

2.AVL树的基本概念

  • 二叉搜索树的性质:对于任何一个节点,它的左子树的所有键值都小于该节点的键值,右子树的所有键值都大于该节点的键值。

  • 平衡因子:AVL树中的每个节点都会有一个平衡因子(balance factor)。

    本文定义平衡因子是该节点的右子树高度减去左子树高度的值。具体来说:

    • 如果平衡因子为 1,说明右子树比左子树高。
    • 如果平衡因子为 -1,说明左子树比右子树高。
    • 如果平衡因子为 0,说明左右子树的高度相同。

    AVL树的要求是:对于每个节点,平衡因子的绝对值不超过1。如果某个节点的平衡因子绝对值大于1,就需要进行旋转操作来恢复平衡。

3.节点的定义

template<class K, class V>
struct AVLTreeNode
{
   
    AVLTreeNode<K, V>* _left;      // 指向左子树的指针
    AVLTreeNode<K, V>* _right;     // 指向右子树的指针
    AVLTreeNode<K, V>* _parent;    // 指向父节点的指针,用于实现三叉链表(Three-pronged chain)
    
    int _bf;                       // 平衡因子 (Balance Factor),用于判断树是否平衡

    pair<K, V> _kv;                // 存储键值对
    
    // 构造函数:初始化一个节点
    AVLTreeNode(const pair<K, V>& kv)
        : _left(nullptr), _right(nullptr), _parent(nullptr), _bf(0), _kv(kv)
    {
   }
};

4.插入

思路

  1. 插入节点
    • 首先执行标准的 二叉搜索树(BST)插入操作。通过循环,遍历树来找到合适的位置,然后插入新的节点 cur
    • 对于每个节点,比较其键 kv.first 来决定插入到左子树还是右子树。
    • 如果树中已经存在相同的键值对(即 kv.first == cur->_kv.first),直接返回 false,表示不插入重复的元素。
  2. 更新平衡因子
    • 如果插入的节点是父节点的左子节点,父节点的平衡因子减 1,如果插入的节点是父节点的右子节点,父节点的平衡因子增 1
    • 如果更新后父节点的平衡因子的值为 0,则说明树的高度没变,更新停止。
    • 如果更新后父节点的平衡因子的值为 1-1,则说明树的高度发生变化,因此继续向上回溯。
    • 如果更新后父节点的平衡因子的值为 2-2,则说明树失衡,旋转处理后树的高度恢复到插入前,更新停止。
template<class K, class V>
class AVLTree
{
   
	typedef AVLTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
    {
   
        // 1. 按照二叉搜索树规则进行插入
        if (!_root)
        {
   
            _root = new Node(kv);
            return true;
        }

        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
   
            parent = cur;
            if (kv.first < cur->_kv.first) cur = cur->_left;
            else if (kv.first > cur->_kv.first) cur = cur->_right;
            else return false;  // 说明已有相同的键,不能插入
        }

        cur = new Node(kv);
        if (kv.first < parent->_kv.first) parent
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值