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;
}
AVL是一种自平衡的二叉查找,它确保了的高度始终保持在对数级别,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。这种数据结构以它的发明者G.M. Adelson-Velsky和E.M. Landis的名字命名[^1]。 ### AVL的定义 - **平衡因子**:每个节点都有一个平衡因子,它是该节点左子的高度减去右子的高度。对于AVL来说,所有节点的平衡因子只能是-1, 0或1。 - **空**:如果T是空,则它自然是一个AVL。 - **非空**:若T不是空,则其左右子TL和TR都必须是AVL,并且对于任意节点,|HL - HR| ≤ 1(其中HL和HR分别表示左子和右子的高度)。 ### AVL的操作 当进行插入或删除操作时,可能会破坏AVL平衡性,这时需要通过旋转来重新恢复平衡: - **单旋转**: - 左单旋(Single Rotate with Left)用于处理左孩子的左子过高。 - 右单旋(Single Rotate with Right)用于处理右孩子的右子过高。 - **双旋转**: - 左右双旋(Double Rotate with Left)用于处理左孩子的右子过高的情况。 - 右左双旋(Double Rotate with Right)用于处理右孩子的左子过高的情况。 这些旋转操作可以保持AVL的性质不变,并且能够快速地调整的结构以维持平衡。 ### AVL的实现 下面是一个简单的C语言代码示例,展示了如何定义AVL的节点以及实现基本的插入操作。这个例子中包含了必要的函数声明和一些核心逻辑。 ```c #include <stdio.h> #include <stdlib.h> // 定义AVL节点结构体 typedef struct AvlNode { int element; struct AvlNode *left; struct AvlNode *right; int height; // 节点的高度 } *AvlTree, *Position; // 获取两个整数中的较大者 int max(int a, int b) { return (a > b) ? a : b; } // 计算给定节点的高度 static int Height(AvlTree T) { if (T == NULL) return -1; // 空节点高度为-1 else return T->height; } // 单旋转 - 左左情况 AvlTree singlerotatewithLeft(AvlTree K2) { Position K1 = K2->left; K2->left = K1->right; K1->right = K2; // 更新节点高度 K2->height = max(Height(K2->left), Height(K2->right)) + 1; K1->height = max(Height(K1->left), K2->height) + 1; return K1; // 新根 } // 单旋转 - 右右情况 AvlTree singlerotatewithRight(AvlTree K2) { Position K1 = K2->right; K2->right = K1->left; K1->left = K2; // 更新节点高度 K2->height = max(Height(K2->left), Height(K2->right)) + 1; K1->height = max(Height(K1->right), K2->height) + 1; return K1; // 新根 } // 双旋转 - 左右情况 AvlTree doublerotatewithLeft(AvlTree K3) { K3->left = singlerotatewithRight(K3->left); return singlerotatewithLeft(K3); } // 双旋转 - 右左情况 AvlTree doublerotatewithRight(AvlTree K3) { K3->right = singlerotatewithLeft(K3->right); return singlerotatewithRight(K3); } // 插入新元素到AVLAvlTree Insert(int x, AvlTree T) { if (T == NULL) { // 如果为空,创建新节点 T = (AvlTree)malloc(sizeof(struct AvlNode)); if (T == NULL) printf("Out of space!!!"); else { T->element = x; T->left = T->right = NULL; T->height = 0; // 新叶节点高度为0 } } else if (x < T->element) { // 向左子插入 T->left = Insert(x, T->left); // 检查并修复平衡 if (Height(T->left) - Height(T->right) == 2) { if (x < T->left->element) T = singlerotatewithLeft(T); // 左左旋转 else T = doublerotatewithLeft(T); // 左右旋转 } } else if (x > T->element) { // 向右子插入 T->right = Insert(x, T->right); // 检查并修复平衡 if (Height(T->right) - Height(T->left) == 2) { if (x > T->right->element) T = singlerotatewithRight(T); // 右右旋转 else T = doublerotatewithRight(T); // 右左旋转 } } // 更新高度 T->height = max(Height(T->left), Height(T->right)) + 1; return T; } ``` 上述代码提供了AVL的基本框架,包括节点定义、插入操作及必要的旋转方法。实际应用中可能还需要添加更多的功能,如删除节点、查找特定值等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值