AVL树(平衡二叉树)

AVL树的概念

一棵AVL树,要么是空树,要么是具有下列性质的二叉搜索树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1。

平衡因子

每个节点都有一个平衡因子,任一节点的平衡因子是-1,0,1。每个节点的平衡因子等于右子树的高度减去左子树的高度。

AVL树的效率

如果一棵搜索二叉树的高度是平衡的,它就是AVL树。如果它有N个节点,它的高度保持在O((log2)N)(log以2为底N的对数),插入,删除,查找的时间复杂度O((log2)N)(log以2为底N的对数)。

平衡化旋转

如果在一棵原来是AVL树中插入一个新节点,造成了不平衡。此时需要进行调整,使之重新平衡化。平衡化旋转分为两类:单旋(左单旋和右单旋)、双旋(左右双旋和右左双旋)。

## 左单旋 ##

这里写图片描述
代码:

    void RotateL(Node* 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)//parent为根节点
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else//ppNode != NULL
        {
            if (parent == ppNode->_left)
                ppNode->_left = subR;
            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 (parent == ppNode->_left)
                subL = ppNode->_left;
            else
                subL = ppNode->_right;
            subL->_parent = ppNode;
        }
        parent->_bf = subL->_bf = 0;
    }

## 左右双旋 ##
有三种情况,由subLR决定:
第一种:(a/b/c/d都不存在,60为新插节点)
这里写图片描述
第二种:
这里写图片描述
第三种:
这里写图片描述
代码:

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;
        }
    }

## 右左双旋##

有三种情况,由subLR决定:
第一种:(a/b/c/d都不存在,60为新插节点)
这里写图片描述
第二种:
这里写图片描述
第三种:
这里写图片描述
代码:

void RotateRL(Node* parent)//右左双旋
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        int bf = subRL->_bf;

        RotateR(subR);
        RotateL(parent);
        //调整平衡因子
        if (bf == 0)
        {
            parent->_bf = subR->_bf = 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;
        }
    }

AVL树的插入

和搜索二叉树的类似,唯一不同的是要调整平衡因子。
parent->_bf == 2 && cur->_bf == 1进行左旋
parent->_bf == -2 && cur->_bf == -1进行右旋
parent->_bf == 2 && cur->_bf == -1进行右左双旋
parent->_bf == -2 && cur->_bf == 1进行左右双旋

代码:

bool Insert(const K& key, const V& value)//插入
    {
        if (_root == NULL)//空树,直接插入
        {
            _root = new Node(key, value);
            return true;
        }

        Node* cur = _root;
        Node* parent = NULL;
        //找插入节点的位置
        while (cur)
        {
            if (key < cur->_key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else if (key > cur->_key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else//已经有该节点,直接返回
            {
                return false;
            }
        }
        //插入节点
        cur = new Node(key, value);

        if (key < parent->_key)
        {   
            parent->_left = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        //调节平衡因子
        while (parent)
        {
            //新插入的节点的父节点改变平衡因子
            if (cur == parent->_left)
                parent->_bf--;
            else
                parent->_bf++;

            //根据平衡因子的大小,进行调整树
            if (parent->_bf == 0)//平衡因子为0,直接返回
                return true;
            else if (abs(parent->_bf) == 1)//平衡因子为正负1,向上继续找
            {
                cur = parent;
                parent = cur->_parent;
            }
            else//平衡因子为正负2,进行旋转
            {
                if (parent->_bf == 2)
                {
                    if (cur->_bf == 1)
                    {
                        RotateL(parent);
                        return true;
                    }
                    else//cur->_bf == -1
                    {
                        RotateRL(parent);
                        return true;
                    }
                }
                else//parent->_bf == -2
                {
                    if (cur->_bf == -1)
                    {
                        RotateR(parent);
                        return true;
                    }
                    else//cur->_bf == 1
                    {
                        RotateLR(parent);
                        return true;
                    }
                }
            }
        }
        return true;
    }

AVL树的查找

和搜索二叉树查找一样

代码:

bool Find(const K& key)//查找
    {
        if (_root == NULL)
            return false;

        Node* cur = _root;

        while (cur)
        {
            if (key < cur->_key)
            {
                cur = cur->_left;
            }
            else if (key > cur->_key)
            {
                cur = cur->_right;
            }
            else
            {
                return true;
            }
        }
        return false;
    }

AVL树的删除

和搜索二叉树的类似,唯一不同的是要调整平衡因子

判断一棵树是不是平衡树

两个条件:1、是搜索二叉树2、左右子树的高度差的绝对值不超过1

代码:

bool IsBalance()//判断是否为平衡树
    {
        if (_root == NULL)
            return true;
        Node* cur = _root;
        //判断左子树和右子树高度差的绝对值是否小于2
        int leftDepth = _Depth(cur->_left);
        int rightDepth = _Depth(cur->_right);
        if (abs(rightDepth - leftDepth) < 2)
            return true;
        else
            return false;
    }

    int _Depth(Node* cur)//递归求树的高度
    {
        if (cur == NULL)
            return 0;
        int left = _Depth(cur->_left);
        int right = _Depth(cur->_right);

        return left > right ? left + 1 : right + 1;
    }

整体代码实现:

"AVLTree.h"
#pragma once

template <class K,class V>
struct AVLTreeNode
{
    K _key;
    V _value;

    int _bf;//平衡因子

    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;

    AVLTreeNode(const K& key,const V& value)//构造函数
        :_key(key)
        , _value(value)
        , _bf(0)
        , _left(NULL)
        , _right(NULL)
        , _parent(NULL)
    {}
};

template <class K,class V>
class AVLTree
{
    typedef AVLTreeNode<K, V> Node;
public:
    AVLTree()//构造函数
        :_root(NULL)
    {}

    ~AVLTree()//析构函数
    {
         _Destory(_root); 
    }

    bool Insert(const K& key, const V& value)//插入
    {
        if (_root == NULL)//空树,直接插入
        {
            _root = new Node(key, value);
            return true;
        }

        Node* cur = _root;
        Node* parent = NULL;
        //找插入节点的位置
        while (cur)
        {
            if (key < cur->_key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else if (key > cur->_key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else//已经有该节点,直接返回
            {
                return false;
            }
        }
        //插入节点
        cur = new Node(key, value);

        if (key < parent->_key)
        {   
            parent->_left = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        //调节平衡因子
        while (parent)
        {
            //新插入的节点的父节点改变平衡因子
            if (cur == parent->_left)
                parent->_bf--;
            else
                parent->_bf++;

            //根据平衡因子的大小,进行调整树
            if (parent->_bf == 0)//平衡因子为0,直接返回
                return true;
            else if (abs(parent->_bf) == 1)//平衡因子为正负1,向上继续找
            {
                cur = parent;
                parent = cur->_parent;
            }
            else//平衡因子为正负2,进行旋转
            {
                if (parent->_bf == 2)
                {
                    if (cur->_bf == 1)
                    {
                        RotateL(parent);
                        return true;
                    }
                    else//cur->_bf == -1
                    {
                        RotateRL(parent);
                        return true;
                    }
                }
                else//parent->_bf == -2
                {
                    if (cur->_bf == -1)
                    {
                        RotateR(parent);
                        return true;
                    }
                    else//cur->_bf == 1
                    {
                        RotateLR(parent);
                        return true;
                    }
                }
            }
        }
        return true;
    }

    bool Find(const K& key)//查找
    {
        if (_root == NULL)
            return false;

        Node* cur = _root;

        while (cur)
        {
            if (key < cur->_key)
            {
                cur = cur->_left;
            }
            else if (key > cur->_key)
            {
                cur = cur->_right;
            }
            else
            {
                return true;
            }
        }
        return false;
    }

    void RotateL(Node* 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)//parent为根节点
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else//ppNode != NULL
        {
            if (parent == ppNode->_left)
                ppNode->_left = subR;
            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 (parent == ppNode->_left)
                subL = ppNode->_left;
            else
                subL = ppNode->_right;
            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(subR);
        RotateL(parent);
        //调整平衡因子
        if (bf == 0)
        {
            parent->_bf = subR->_bf = 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 InOrder()//中序打印
    {
        _InOrder(_root);
        cout << endl;
    }

    bool IsBalance()//判断是否为平衡树
    {
        if (_root == NULL)
            return true;
        Node* cur = _root;
        //判断左子树和右子树高度差的绝对值是否小于2
        int leftDepth = _Depth(cur->_left);
        int rightDepth = _Depth(cur->_right);
        if (abs(rightDepth - leftDepth) < 2)
            return true;
        else
            return false;
    }

protected:
    void _Destory(Node* root)  //销毁
    {  
        if (root == NULL)  
            return;  
        _Destory(root->_left);  
        _Destory(root->_right);  
        delete root;  
    }  
    int _Depth(Node* cur)//递归求树的高度
    {
        if (cur == NULL)
            return 0;
        int left = _Depth(cur->_left);
        int right = _Depth(cur->_right);

        return left > right ? left + 1 : right + 1;
    }

    void _InOrder(Node* cur)
    {
        if (cur == NULL)
            return;
        _InOrder(cur->_left);
        cout << cur->_key << " ";
        _InOrder(cur->_right);
        }

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 };
    AVLTree<int, int> t;
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    {
        t.Insert(a[i],i);
    }
    t.InOrder();
    cout << "IsBalance?" << t.IsBalance() << endl;


    t.Find(4);
    t.Find(2);
    t.Find(6);
    t.Find(8);
    t.Find(16);
    t.Find(18);
    t.Find(0);
    t.Find(100);
}
"Test.c"
#include <iostream>
#include <stdlib.h>

using namespace std;

#include "AVLTree.h"

int main()
{
    TestAVLTree();
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值