AVL树

1.AVL树的概念

  • AVL树
    AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel’son-Vel’skii和E.M.Landis提出来的。它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度
  • AVL树的性质
    1.左子树和右子树的高度之差的绝对值不超过1
    2.中的每个左子树和右子树都是AVL树
    3.每个节点都有一个平衡因子(balance factor–bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子树的高度 )

2.平衡化旋转

(1)左单旋转

如下图所示,a,b,c均为高度为h的子树。当插入节点d时,影响了c子树的高度及平衡因子,以及节点2的平衡因子。
此时,需要调整这棵树(左旋),使得平衡因子的绝对值小于2;
这里写图片描述
代码:

//左旋
    void _RotateL(Node* parent)
    {
        assert(parent);
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if (subRL)
        {
            subRL->_parent = parent;
        }
        Node* ppNode = parent->_parent;
        subR->_left = parent;
        parent->_parent = subR;
        if (ppNode == NULL)
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subR;
                subR->_parent = ppNode;
            }
            else
            {
                ppNode->_right = subR;
                subR->_parent = ppNode;
            }
        }
        parent->_bf = subR->_bf = 0;
    }
(2)右单旋转

右旋与左旋类似,只是方向方向刚好相反。
这里写图片描述
代码:

//右旋
    void _RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if (subLR)
        {
            subLR->_parent = parent;
        }
        Node* ppNode = parent->_parent;
        subL->_right = parent;
        parent->_parent = subL;

        if (ppNode == NULL)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subL;
                subL->_parent = ppNode;
            }
            else
            {
                ppNode->_right = subL;
                subL->_parent = ppNode;
            }
        }
        parent->_bf = subL->_bf = 0;
    }
(3)先左后右双旋转

先左后右双旋转分为三种情况
1>subLR的平衡因子为0
只有当a,b不存在且节点2为插入的节点时,才需要左右旋转。
先以节点1为轴左旋,再以节点3为轴右旋,完成旋转。
这里写图片描述
2>subLR的平衡因子为1
先以节点1为轴左旋,再以节点3为轴右旋,完成旋转。
这里写图片描述
3>subLR的平衡因子为-1
先以节点1为轴左旋,再以节点3为轴右旋,完成旋转。
这里写图片描述
旋转完成后更新平衡因子
旋转后的平衡因子如下:

subLR->_bfparentsubLsubLR
0000
10-10
-1100

代码:

void _RotateLR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        int bf = subLR->_bf;
        _RotateL(subL);
        _RotateR(parent);

        if (bf == 0)
        {
            parent->_bf = subL->_bf = subLR->_bf = 0;
        }

        else if (bf == 1)
        {
            parent->_bf = 0;
            subL->_bf = -1;
            subLR->_bf = 0;
        }
        else  //bf == -1
        {
            parent->_bf = 1;
            subL->_bf = 0;
            subLR->_bf = 0;
        }
    }
(4)先右后左双旋转

与先左后右双旋转类似,就不详细介绍了。
代码:

void _RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;

        _RotateR(parent->_right);
        _RotateL(parent);

        if (bf == 0)
        {
            parent->_bf = 0;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else if (bf == 1)
        {
            parent->_bf = -1;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else    //bf == -1
        {
            parent->_bf = 0;
            subR->_bf = 1;
            subRL->_bf = 0;
        }
    }

3.AVL树的插入

(1)找到要插入的位置
        if (_root == NULL)
        {
            _root = new Node(key);
            return true;
        }
        Node* cur = _root;
        Node* parent = NULL;
        //找到要插入的节点的位置
        while (cur)
        {
            if (key > cur->_key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (key < cur->_key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;   //表示已经存在,就不再插入了
            }
        }
(2)插入节点
        cur = new Node(key);
        if (key > parent->_key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }
(3)更新平衡因子
//更新平衡因子,分三种情况
        while (parent)
        {
            if (parent->_left == cur)
                parent->_bf--;
            else
                parent->_bf++;
            //1.
            if (parent->_bf == 0)
            {
                return true;
            }
            //2.
            else if (abs(parent->_bf) == 1)
            {
                cur = parent;
                parent = cur->_parent;
            }
            //3.
            else   //abs(parent->_bf) == 2
            {
                Node* subL = parent->_left;
                Node* subR = parent->_right;
                if (parent->_bf == -2 && subL->_bf == -1)
                {
                    _RotateR(parent);
                    return true;
                }
                else if (parent->_bf == 2 && subR->_bf == 1)
                {
                    _RotateL(parent);
                    return true;
                }
                else if (parent->_bf == -2 && subL->_bf == 1)
                {
                    _RotateLR(parent);
                    return true;
                }
                else // (parent->_bf == 2 && subR->_bf == -1)
                {
                    _RotateRL(parent);
                    return true;
                }
            }
        }

4.判断一个二叉树是否AVL树

一颗二叉树为AVL,得同时满足是搜索二叉树(节点左孩子的值小于节点的值,节点右孩子的值大于节点的值)及这棵树平衡(左右子树的高度差不超过1)。
代码:

bool IsAVL()
    {
        if (IsBST(_root) && IsBalance(_root))
        {
            return true;
        }
        return false;
    }
bool IsBST(Node* root)
    {
        if (root == NULL)
        {
            return true;
        }   
        Node* left = root->_left;
        Node* right = root->_right;
        if (left && left->_key < root->_key)
        {
            return IsBST(root->_left);
        }
        else if (right && right->_key > root->_key)
        {
            return IsBST(root->_right);
        }

    }
    bool IsBalance(Node* root)
    {
        if (root == NULL)
            return true;
        int rightHeight = _Height(root->_right);
        int leftHeight = _Height(root->_left);
        int diff = rightHeight - leftHeight;
        return abs(diff) < 2 && IsBalance(root->_left) && IsBalance(root->_right);
    }
    int _Height(Node* node)
    {
        if (node == NULL)
            return 0;
        int right = _Height(node->_right) + 1;
        int left = _Height(node->_left) + 1;
        return right > left ? right : left;
    }

5.完整代码:

#pragma once
#include <iostream>
#include <assert.h>
#include <stdlib.h>
using namespace std;

template <class K>
struct AVLTreeNode
{
    K _key;
    int _bf;    //平衡因子
    AVLTreeNode<K>* _left;
    AVLTreeNode<K>* _right;
    AVLTreeNode<K>* _parent;
    AVLTreeNode(const K& key)
        :_key(key)
        , _bf(0)
        , _left(NULL)
        , _right(NULL)
        , _parent(NULL)
    {}
};

template <class K>
class AVLTree
{
public:
    typedef AVLTreeNode<K> Node;
public:
    AVLTree()
        :_root(NULL)
    {}

    ~AVLTree()
    {
        _Destroy(_root);
    }

    bool Insert(const K& key)
    {
        if (_root == NULL)
        {
            _root = new Node(key);
            return true;
        }
        Node* cur = _root;
        Node* parent = NULL;
        //找到要插入的节点的位置
        while (cur)
        {
            if (key > cur->_key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (key < cur->_key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;   //表示已经存在,就不再插入了
            }
        }
        //插入节点
        cur = new Node(key);
        if (key > parent->_key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }


        //更新平衡因子
        while (parent)
        {
            if (parent->_left == cur)
                parent->_bf--;
            else
                parent->_bf++;
            if (parent->_bf == 0)
            {
                return true;
            }

            else if (abs(parent->_bf) == 1)
            {
                cur = parent;
                parent = cur->_parent;
            }
            else   //abs(parent->_bf) == 2
            {
                Node* subL = parent->_left;
                Node* subR = parent->_right;
                if (parent->_bf == -2 && subL->_bf == -1)
                {
                    _RotateR(parent);
                    return true;
                }
                else if (parent->_bf == 2 && subR->_bf == 1)
                {
                    _RotateL(parent);
                    return true;
                }
                else if (parent->_bf == -2 && subL->_bf == 1)
                {
                    _RotateLR(parent);
                    return true;
                }
                else // (parent->_bf == 2 && subR->_bf == -1)
                {
                    _RotateRL(parent);
                    return true;
                }
            }
        }
        return true;
    }
    void InOrder()//中序遍历
    {
        _InOrder(_root);
        cout << endl;
    }
    bool IsAVL()
    {
        if (IsBST(_root) && IsBalance(_root))
        {
            return true;
        }
        return false;
    }
protected:
    bool IsBST(Node* root)
    {
        if (root == NULL)
        {
            return true;
        }   
        Node* left = root->_left;
        Node* right = root->_right;
        if (left && left->_key < root->_key)
        {
            return IsBST(root->_left);
        }
        else if (right && right->_key > root->_key)
        {
            return IsBST(root->_right);
        }

    }
    bool IsBalance(Node* root)
    {
        if (root == NULL)
            return true;
        int rightHeight = _Height(root->_right);
        int leftHeight = _Height(root->_left);
        int diff = rightHeight - leftHeight;
        return abs(diff) < 2 && IsBalance(root->_left) && IsBalance(root->_right);
    }
    int _Height(Node* node)
    {
        if (node == NULL)
            return 0;
        int right = _Height(node->_right) + 1;
        int left = _Height(node->_left) + 1;
        return right > left ? right : left;
    }
    void _InOrder(Node* root)
    {
        if (root != NULL)
        {
            _InOrder(root->_left);
            cout << root->_key << " ";
            _InOrder(root->_right);
        }
    }
    //左旋
    void _RotateL(Node* parent)
    {
        assert(parent);
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if (subRL)
        {
            subRL->_parent = parent;
        }
        Node* ppNode = parent->_parent;
        subR->_left = parent;
        parent->_parent = subR;
        if (ppNode == NULL)
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subR;
                subR->_parent = ppNode;
            }
            else
            {
                ppNode->_right = subR;
                subR->_parent = ppNode;
            }
        }
        parent->_bf = subR->_bf = 0;
    }

    //右旋
    void _RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if (subLR)
        {
            subLR->_parent = parent;
        }
        Node* ppNode = parent->_parent;
        subL->_right = parent;
        parent->_parent = subL;

        if (ppNode == NULL)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subL;
                subL->_parent = ppNode;
            }
            else
            {
                ppNode->_right = subL;
                subL->_parent = ppNode;
            }
        }
        parent->_bf = subL->_bf = 0;
    }

    void _RotateLR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        int bf = subLR->_bf;
        _RotateL(subL);
        _RotateR(parent);

        if (bf == 0)
        {
            parent->_bf = subL->_bf = subLR->_bf = 0;
        }

        else if (bf == 1)
        {
            parent->_bf = 0;
            subL->_bf = -1;
            subLR->_bf = 0;
        }
        else  //bf == -1
        {
            parent->_bf = 1;
            subL->_bf = 0;
            subLR->_bf = 0;
        }
    }
    void _RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;

        _RotateR(parent->_right);
        _RotateL(parent);

        if (bf == 0)
        {
            parent->_bf = 0;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else if (bf == 1)
        {
            parent->_bf = -1;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else    //bf == -1
        {
            parent->_bf = 0;
            subR->_bf = 1;
            subRL->_bf = 0;
        }
    }
    void _Destroy(Node* root)
    {
        if (root == NULL)
            return;
        _Destroy(root->_left);
        _Destroy(root->_right);
        delete root;
        root = NULL;
    }
    protected:
        Node* _root;
};

void TestAVLTree()
{
    /*int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };*/
    int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    int size = sizeof(a) / sizeof(a[0]);
    AVLTree<int> a1;
    for (int i = 0; i < size; i++)
    {
        a1.Insert(a[i]);
        cout << a[i]<<"IsAVL:" << a1.IsAVL() << endl;
    }
    a1.InOrder();
    cout << "IsAVL:" << a1.IsAVL() << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值