AVL平衡树的插入

news2024/9/30 1:35:40

//AVL搜索树
//对数据的搜索: 1:暴力查找遍历 
//              2:二叉树 有序,但是伴随着插入删除,维护成本很高
//              3:二叉搜索树  问题:在极端情况下,会退化成最开始的链表
//              4:二叉高度平衡搜索树  AVL树/红黑树 
template <typename Key, typename Value>
struct AVLTreeNode
{
    pair < Key, Value > _kv;
    int _bf;   //balance factor 平衡因子
    AVLTreeNode<Key, Value>* _left;
    AVLTreeNode<Key, Value>* _right;
    AVLTreeNode<Key, Value>* _parent;
    AVLTreeNode(const pair<Key, Value>& kv)
        :_kv(kv)
        , _bf(0)
        , _left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
    { }
};
template <typename Key, typename Value>
class AVLTree
{
    typedef AVLTreeNode<Key, Value> Node;
public:
    bool insert(const pair<Key, Value>& kv)
    {
        if (_root == nullptr)
        {
            _root = new Node(kv);
            return true;
        }
        //插入数据
        Node* cur = _root;
        Node* parent = cur;
        while (cur)
        {
            parent = cur;
            if (kv.first == cur->_kv.first)
            {
                return false;
            }
            else if (kv.first > cur->_kv.first)
            {
                cur = cur->_right;
            }
            else if (kv.first < cur->_kv.first)
            {
                cur = cur->_left;
            }
        }
        cur = new Node(kv);
        if (parent->_kv.first < kv.first)
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }
        cur->_parent = parent;
        //更新平衡因子
        //1:平衡因子,结点的右子树的高度减去左子树的高度,新增节点cur在右边时,父节点平衡因子++,反之--;
        //2:平衡因子为0时,表示树的和高度没有变化,不会影响起祖先
        //3:平衡因子为1/-1时,表示parent的树高度有变化,会影响其祖先
        while (parent)
        {
            if (cur == parent->_left)
            {
                parent->_bf--;
            }
            else
            {
                parent->_bf++;
            }

            if (parent->_bf == 0)//不会影响祖先,直接更新完毕
            {
                break;
            }
            else if (abs(parent->_bf) == 1)//平衡因子为1 / -1时,表示parent的树高度有变化,会影响其祖先
            {
                cur = parent;
                parent = parent->_parent;
            }
            else if (abs(parent->_bf) == 2)//4:平衡因子为2/-2时,表示parent的树高度已经需要旋转,降低树的高度
            {
                //左单旋parent平衡因子为2,右高左低,单边cur为1,将cur为1的结点作为新的父节点,原先的父界点作cur的子节点
                if (parent->_bf == 2 && cur->_bf == 1)//左单旋
                {
                    RotateL(parent);
                }
                else if (parent->_bf == -2 && cur->_bf == -1)   //右单旋
                {
                    RotatelR(parent);
                }
                else if (parent->_bf == 2 && cur->_bf == -1) //预处理右旋+左单旋
                {
                    RotatelRL(parent);
                }
                else if (parent->_bf == -2 && cur->_bf == 1)  //预处理左单旋+右旋
                {
                    RotatelLR(parent);
                }
            }
            else//4:平衡因子既不是0,也不是1,-1,不是2,-2时,表示程序;已经出现了bug
            {
                assert(false);
            }
        }

        return true;
    }


    void RotateL(Node*& parent)  //左单旋 调整父子节点树中顺序,建立链接(parent与cur,parent的parent与cur),调整平衡因子
    {
        Node* cur = parent->_right;
        Node* cur_left = cur->_left;

        parent->_right = cur_left;//将cur的左节点放入parent的右结点
        if (cur_left)
        {
            cur_left->_parent = parent;  //cur_left控制_parent
        }

        cur->_left = parent;//将parent放入cur的左节点
        Node* ppNode = parent->_parent;
        cur->_parent = parent->_parent; //cur的父节点为原parent的父亲
        parent->_parent = cur; //parent的父节点为cur
        if (parent == _root)   //建议原先父节点的父节点与cur的链接
        {
            _root = cur;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = cur;
            }
            else
            {
                ppNode->_right = cur;
            }
        }
        parent->_bf = cur->_bf = 0;
    }


    void RotatelR(Node*& parent) //右单旋 调整父子节点树中顺序,建立链接(cur_right(?空)与parent,parent与cur,parent的parent(root?)与cur),调整平衡因子
    {
        Node* cur = parent->_left;
        Node* cur_right = cur->_right;

        parent->_left = cur_right;//1:将cur的右节点放入parent的左结点
        if (cur_right)
        {
            cur_right->_parent = parent;  //cur_right控制_parent
        }

        cur->_right = parent;//2:将parent放入cur的右节点
        Node* ppNode = parent->_parent;
        cur->_parent = parent->_parent; //cur的父节点为原parent的父亲
        parent->_parent = cur; //parent的父节点为cur
        if (parent == _root)   //建议原先父节点的父节点与cur的链接
        {
            _root = cur;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = cur;
            }
            else
            {
                ppNode->_right = cur;
            }
        }
        parent->_bf = cur->_bf = 0;
    }


    void RotatelRL(Node*& parent)  //预处理右旋+左单旋
    {
        Node* cur = parent->_right;
        Node* cur_left = cur->_left;
        int bf = cur_left->_bf;

        RotatelR(parent->_right);
        RotateL(parent);

        if (bf == 1)
        {
            parent->_bf = -1;
        }
        if (bf == -1)
        {
            cur->_bf = 1;
        }
    }


    void RotatelLR(Node*& parent) //预处理左单旋+右旋
    {
        Node* cur = parent->_left;
        Node* cur_right = cur->_right;
        int bf = cur_right->_bf;

        RotateL(cur);
        RotatelR(parent);

        if (bf == 1)
        {
            cur->_bf = -1;
        }
        if (bf == -1)
        {
            parent->_bf = 1;
        }
    }
    

//判断调试AVl平衡代码
    //int Height(Node* root) //树的高度
    //{
    //    if (root == nullptr)
    //        return 0;

    //    int leftHeight = Height(root->_left);
    //    int rightHeight = Height(root->_right);

    //    return leftHeight > rightHeight ? leftHeight++ : rightHeight++;
    //}
    //bool isBalance()
    //{
    //    return _isBalance(_root);
    //}
    //bool _isBalance(Node* root) //root为私有节点
    //{
    //    if (root == nullptr)
    //        return true;
    //    
    //    int leftHight = Height(root->_left);
    //    int rightHight = Height(root->_right);

    //    //检查平衡因子
    //    if (rightHight - leftHight != root->_bf)
    //    {
    //        cout << "_bf:error:" << root->_kv.first << "factual:" << rightHight - leftHight << "now" << root->_bf << endl;
    //        return false;
    //    }
    //    return abs(rightHight - leftHight)<2
    //        && isBalance(root->_left)
    //        && isBalance(root->_right)
    //}

private:
    Node* _root = nullptr;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

inne所属公司抢注“童年时光”商标仍被冻结

根据中国商标网查询&#xff0c;国家知识产权局已于2023年3月10日裁定&#xff0c;被告inne所属的南京童年时光生物技术有限公司注册的“童年时光”商标无效。随着这起保健品行业品牌资产争夺事件的发酵&#xff0c;更多的细节得到披露&#xff0c;至此&#xff0c;一个从“代理…

低代码+RPA,会发生什么?

据相关研究表明&#xff0c;每个企业员工每天至少花1-2个小时完成文件归档、数据输入等工作&#xff0c;而这些工作都是可以通过自动化的方式完成的。 如今&#xff0c;不少企业正专注于工作流程自动化&#xff0c;希望能花最少的时间完成重复性工作&#xff0c;机器人流程自动…

Python基础入门(17)----Python虚拟环境:为何要用虚拟环境、如何使用virtualenv

文章目录 在Python开发中,虚拟环境是一个独立的目录树,可以在其中安装Python模块。每个虚拟环境都有自己的Python二进制文件和一组安装的库。使用虚拟环境的主要原因是为了避免项目间的依赖冲突,允许每个项目有其特定的依赖,而不影响全局安装的模块。 为何要用虚拟环境 依…

Vue 最简单路由 页面路由 配置路由

路由安装 Vue3使用 vue-router4 Vue2使用 vue-router3 npm i vue-router3创建路由文件 配置路由规则 import Vue from vue import VueRouter from vue-router //导入路由器 Vue.use(VueRouter)import Login from ../components/Login import User from ../components/User //…

17、Python虚拟环境:为何要用虚拟环境、如何使用virtualenv

文章目录 在Python开发中,虚拟环境是一个独立的目录树,可以在其中安装Python模块。每个虚拟环境都有自己的Python二进制文件和一组安装的库。使用虚拟环境的主要原因是为了避免项目间的依赖冲突,允许每个项目有其特定的依赖,而不影响全局安装的模块。 为何要用虚拟环境 依…

Linux 进程的管道通信

文章目录 无名管道pipe有名管道 进程之间的通信&#xff1a;Linux环境下&#xff0c;进程地址空间相互独立&#xff0c;每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另外一个进程中都看不到&#xff0c;所以进程之间不能相互访问&#xff0c;要交换数据必须通过…

分享68个毕业答辩PPT,总有一款适合您

分享68个毕业答辩PPT&#xff0c;总有一款适合您 链接&#xff1a;https://pan.baidu.com/s/1trwZ8T2I2rFh59LVxTSXTw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知识付费甚欢…

开源DB-GPT实现连接数据库详细步骤

官方文档&#xff1a;欢迎来到DB-GPT中文文档 — DB-GPT &#x1f44f;&#x1f44f; 0.4.1 第一步&#xff1a;安装Minicoda https://docs.conda.io/en/latest/miniconda.html 第二步&#xff1a;安装Git Git - Downloading Package 第三步&#xff1a;安装embedding 模型到…

TFTP协议详解

1.简介 TFTP&#xff08;Trivial File Transfer Protocol,简单文件传输协议&#xff09;是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议&#xff0c;提供不复杂、开销不大的文件传输服务。端口号为69。 FTP是一个传输文件的简单协议&#xff0c;它基…

亚马逊怎么下单更真实

亚马逊是一个知名的在线购物平台&#xff0c;为了下单更真实&#xff0c;可以采取以下步骤&#xff1a; 1、查看商品信息&#xff1a;在浏览亚马逊的商品时&#xff0c;仔细查看商品描述、照片和客户评价。这些信息可以帮助你了解产品的真实情况。 2、对比价格&#xff1a;比…

Android Studio(项目打包成APK)

打包流程 直接上图即可 按照上面操作后&#xff0c;即可以开始打包&#xff0c;一般第一次打包都需要几分钟&#xff08;我第一次打包花了七八分钟&#xff09;&#xff0c;如果打包错误了也别担心&#xff0c;可以查看错误分析一下原因&#xff0c;实在不行可以把错误放到网站…

macos端串口调试推荐 serial直装激活 for mac

serial for mac版软件特色 1.准备好macOS High Sierra 最近的升级是否会让您的设备落后&#xff1f;Serial将使其恢复正常工作&#xff0c;同时保持Mac的安全功能完好无损。 2.完美无瑕的仿真 Serial是一个全功能的终端仿真器&#xff0c;支持Xterm&#xff0c;VT102和ANSI…

软件测试/测试开发丨PyCharm安装指南与技巧分享

点此获取更多相关资料 PyCharm 简介 工欲善其事&#xff0c;必先利其器。为了良好的学习体验&#xff0c;我们需要一款功能全面&#xff0c;并且容易上手的代码编辑器&#xff0c;那么首选大名鼎鼎的 PyCharm。 PyCharm 是一款功能强大的 Python 集成化开发工具&#xff0c;…

Linux系统CH347应用—GPIO输出输入与中断功能

Linux/安卓系统可使用CH347转接GPIO功能&#xff0c;所有GPIO均为双向IO口&#xff0c;支持输出与输入切换&#xff0c;输出时为推挽输出结构&#xff0c;具有较强驱动能力&#xff0c;输入时内部为弱上拉输入&#xff0c;上拉能力较弱。此外&#xff0c;用作输入的GPIO还支持G…

C# TCP Server服务端多线程监听RFID读卡器客户端上传的读卡数据

本示例使用设备介绍&#xff1a;液显WIFI无线网络HTTP协议RFID云读卡器可编程实时可控开关TTS语-淘宝网 (taobao.com) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using Sy…

【Sql】sql server数据库提示:执行Transact-SQL语句或批处理时发生了异常。 无法打开数据库msdb,错误:926。

【问题描述】 打开sql server2008r2数据库的时候&#xff0c; 系统提示执行Transact-SQL语句或批处理时发生了异常。 无法打开数据库msdb&#xff0c;错误&#xff1a;926。 【概念理解】 首先MSDB数据库是的作用&#xff1a; 用于给SQL Server代理提供必要的信息来运行调度警…

89㎡现代风格,年轻人都向往的家!福州中宅装饰,福州装修

对于美好家的向往&#xff0c;是每位业主的需求。 大到每一个工艺&#xff0c;小到每一道装修程序&#xff0c;我们都以认真的态度&#xff0c;用专业的服务品质将家装的理念深入到每户业主的内心,赢得了上万千业主的支持和肯定。 怀着最初的一颗匠心,对于每一项工艺都认真钻研…

宽带服务预约小程序的内容

宽带有很高的需求度&#xff0c;无论是企业办公楼还是家庭场景&#xff0c;对网络的需求度都比较高&#xff0c;而宽带安装服务商也往往有不少生意&#xff0c;但在实际发展中也面对着一些痛点&#xff1a; 1、服务传播套餐展示难 宽带业务的需求度不低&#xff0c;但依然有很…

Redis注解式开发结合SSM项目使用与Quartz框架介绍以及击穿、穿透、雪崩问题解决

目录 一、SSM项目整合Redis 1.1 导入pom依赖 1.2 spring-redis.xml 1.3 spring上下文配置 二、Redis注解式开发 2.1 Cacheable 注解 2.2 自定义策略 2.3 CachePut 注解 三、Redis中缓冲、击穿、穿透、雪崩问题解决 3.1 缓冲问题 —— Quartz 框架 3.2 常见的三种问题…

备份扫描工具 god_bak

Part1 前言 不想写东西&#xff0c;或者说换种说法 有些东西还没写完&#xff0c;有些系列也还没整完。就放一个昨天摸鱼写的东西。 如图&#xff0c;每个系列都还是会按照自己的风格来写&#xff0c;代码审计实战等都会结合自己挖掘或审计过的案例进行结合知识点的风格去写&…