AVL 树

由于之前的搜索二叉树在单支树的情况下,时间复杂度依然为 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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值