C++AVL树

查找元素相当 于在顺序表中搜索元素,效率低下**。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年 发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之 差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。 一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在O(logN),搜索时 间复杂度O(logN)。

AVL数的原理实现

AVL数的定义
#include <vector>
#include <stack>

namespace km{
    template <class T>
    class TreeNode{
        int m_bf;//记录平衡因子
        T m_data;
        TreeNode<T> * m_left;
        TreeNode<T> * m_right;
        TreeNode<T> * m_parent;
    public:
        TreeNode(const T &val = T()):
        m_bf(0),
        m_data(val),
        m_left(nullptr),
        m_right(nullptr),
        m_parent(nullptr){}

        template <class U>
        friend class AVLTree;
    };

    template <class T>
    class AVLTree{
        TreeNode<T> * m_root;

        void destory(TreeNode<T> *root){
            if(root){
                destory(root->m_left);
                destory(root->m_right);
                delete root;
            }
        }
        
    public:
        AVLTree():
            m_root(nullptr){
        }

        ~AVLTree(){
            destory(m_root);
        }
AVL数的插入

AVL树的插入是其最有魅力的一个部分, 为了保证上述条件的存在, AVL在每插入一个节点后其平衡因子都会进行判断是否发生改变, 如果出现不符合要求的情况, 就会发生**旋转(左旋, 右旋)**来保证平衡条件继续成立

		bool insert(const T &val){
            //1. 先按照二叉搜索树的规则将节点插入到AVL树中
            if(m_root == nullptr){
                m_root = new TreeNode<T>(val);
                return true;
            }

            TreeNode<T> *cur = m_root;
            TreeNode<T> * pre = nullptr;

            while (cur){
                if(val < cur->m_data){
                    pre = cur;
                    cur = cur->m_left;
                } else if(val > cur->m_data){
                    pre = cur;
                    cur = cur->m_right;
                } else {
                    return false;
                }
            }

            cur = new TreeNode<T>(val);
            if(val < pre->m_data){
                pre->m_left = cur;
            } else {
                pre->m_right = cur;
            }

            cur->m_parent = pre;

            // 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,
            // 此时就需要更新平衡因子,并检测是否破坏了AVL树的平衡性
            while (pre){
                if (pre->m_left == cur){
                    pre->m_bf--;
                } else {
                    pre->m_bf++;
                }

                if(pre->m_bf == 0){
                    break;
                } else if(pre->m_bf == 1 || pre->m_bf == -1){
                    cur = pre;
                    pre = pre->m_parent;
                } else {
                    if (pre->m_bf == 2){
                        //pre的平衡因子为2, 则分为两种情况
                        if(cur->m_bf == 1){
                            //cur平衡因子为1则说明cur的右子树比左子树高1,此时左旋
                            lRound(pre);
                        } 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0AprCJLl-1575812442292)(D:\289437926\FileRecv\MobileFile\img_0289.png)]

						else {
                            //否则cur平衡因子为-1则说明cur的左子树比右子树高1,此时先左旋再右旋
                            rlRound(pre);
                        }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vMlTeuq1-1575812442293)(D:\289437926\FileRecv\MobileFile\img_0292.png)]

					} else {
                        if(cur->m_bf == 1){
                            //cur平衡因子为1则说明cur的右子树比左子树高1,此时先左旋再右旋
                            lrRound(pre);
                        }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pKu7Ze6y-1575812442295)(D:\289437926\FileRecv\MobileFile\img_0293.png)]

						 else {
                            //否则cur平衡因子为-1则说明cur的左子树比右子树高1,此时右旋
                            rRound(pre);
                        }
                    }
                    break;
                }
            }
            return true;
        }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DN02nizC-1575812442296)(D:\289437926\FileRecv\MobileFile\img_0291.png)]

std::vector<T> InOrder(){
            std::stack<TreeNode<T> *> s;
            std::vector<T> res;
            TreeNode<T> * cur = m_root;

            while (cur || !s.empty()){
                for (; cur; cur = cur->m_left){
                    s.push(cur);
                }
                if (!s.empty()){
                    cur = s.top();
                    res.push_back(cur->m_data);
                    s.pop();

                    cur = cur->m_right;
                }
            }
            return res;
        }
    };
};

AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证 查询时高效的时间复杂度,即logN 。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如: 插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。 因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树, 但一个结构经常修改,就不太适合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值