c++--AVL树简单实现

news2024/9/22 17:37:39

1.什么是AVL树

AVL树就是在搜索二叉树的基础上通过控制左右子树的高度差实现的,在搜索二叉树的基础上,通过旋转来控制,是左右子树高度差的绝对值严格控制为不超过1(通过旋转来控制树的高度)。由于搜索二叉树的效率最差为O(N-1)次,(n为节点个数),所以为了减少查找时间而创造了AVL树,

当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

2.AVL树的定义

一颗AVL树或者是空树,是具有以下性质的树:

1.他的左右子树都是AVL树

2.左右高度差的绝对值不超过1(即1,0,-1)

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

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么,AVL树的插入过程可以分为两步:
1. 按照二叉搜索树的方式插入新节点
2. 调整节点的平衡因子

标准AVL树

 3. AVL树的实现

AVL树最重要的就是旋转,需要控制左右子树高度差的绝对值不超过1,因此,平衡因子可能存在三种情况,即0,正负1,正负2,

1. 如果平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整成0,此时满足AVL树的性质,插入成功

2. 如果平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1,此时以pParent为根的树的高度增加,需要继续向上更新。
3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进行旋转处理。

如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,
使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:

1.新节点插入较高左子树的左侧---左左:右单旋

 2.新插入节点较高右子树的右侧:左旋转

 3.新节点插入较高左子树的右侧---左右:先左单旋再右单旋

 4.. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

 4.代码实现

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
namespace _3s
{
    template<class K, class V>
    struct AVLTreeNode
    {
        AVLTreeNode* _left;
        AVLTreeNode* _right;
        AVLTreeNode* _parent;
        std::pair<K, V> _KV;
        int bf;
        AVLTreeNode(const std::pair<K, V> kv)
            :_left(nullptr)
            , _right(nullptr)
            , _parent(nullptr)
            , _KV(kv)
            , bf(0)
        {}
    };
    //节点 
    template<class K, class V>
    class AVLTree
    {
        typedef AVLTreeNode<K, V> Node;
    public:
        //插入
        bool insert(const std::pair<K, V>& kv)
        {
            if (root == nullptr)
            {
                root = new Node(kv);
                return true;
            }
            Node* parent = nullptr;
            Node* cur = root;
            while (cur)
            {
                if (cur->_left.first < kv.first)
                {
                    parent = cur;
                    cur = cur->_right;
                }
                else if (cur->_left.first > kv.first)
                {
                    parent = cur;
                    cur = cur->_left;
                }
                else
                {
                    return false;
                }
            }
            cur = new Node(kv);
            if (parent->_kv.first > kv.first)
            {
                parent->left = cur;
                parent->bf--;
            }
            else
            {
                parent->right = cur;
                parent->bf++;
            }
            cur->_parent = parent;
            while (parent)
            {


                if (abs(parent->bf) == 1)
                {
                    parent = parent->_parent;
                    cur = cur->_parent;

                }
                else if (abs(parent->bf) == 2)
                {
                    if (parent->_bf == 2 && cur->_bf == 1)
                    {
                        RotateL(parent);
                    }
                    else if ((parent->_bf == -2 && cur->_bf == -1))
                    {
                        RotateR(parent);
                    }
                    else if (parent->_bf == -2 && cur->_bf == 1)
                    {
                        RotateLR(parent);
                    }
                    break;
                }
                else
                {
                    assert(false);
                }
            }
            return true;
        }
    private:
        //左旋转
        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 (root == parent)
            {
                root = subR;
                subR->_parent = nullptr;
            }
            else
            {
                if (ppNode->_left == parent)
                {
                    ppNode->_left = subR;
                }
                else
                {
                    ppNode->_right = subR;
                }
                subR->_parent = ppNode;
            }
            subR->_bf = parent->_bf = 0;
        }
        //右旋转
        void RotateR(Node* parent)
        {
            Node* subL = parent->_left;
            Node* subLR = subR->_right;

            parent->_left = subRL;
            if (subRL)
                subRL->_parent = parent;
            Node* ppNode = parent->_parent;
            subL->_right = parent;
            parent->_parent = subL;
            if (root == parent)
            {
                root = subL;
                subL->_parent = nullptr;
            }
            else
            {
                if (ppNode->_left == parent)
                {
                    ppNode->_left = subL;
                }
                else
                {
                    ppNode->_right = subL;
                }
                subR->_parent = ppNode;
            }
            subL->_bf = parent->_bf = 0;
        }
         //左右旋转
        void RotateLR(Node* parent)
        {
            Node* subL = parent->_left;
            Node* subLR = subL->_right;
            int _bf = subLR->bf;
            RotateL(parent->_left);
            RotateR(parent);

            subLR->bf = 0;
            if (_bf == 1)
            {
                parent->_bf = 0;
                subL->_bf = -1;
            }
            else if (_bf == -1)
            {
                parent->bf = 1;
                subL->bf = 0;
            }
            else if (_bf == 0)
            {
                parent->bf = 0;
                subL->bf = 0;
            }
            else
            {
                assert(false);
            }


        }
        //右左旋转
        void RotateRL(Node* parent)
        {

            Node* subR = parent->_right;
            Node* subRL = subL->_left;
            int _bf = subLR->bf;
            RotateR(parent->_right);
            RotateL(parent);

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

        }
    private:
        Node* root = nullptr;
    };
}


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

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

相关文章

一起学SF框架系列7.1-spring-AOP-基础知识

AOP(Aspect-oriented Programming-面向切面编程&#xff09;是一种编程模式&#xff0c;是对OOP(Object-oriented Programming-面向对象编程&#xff09;一种有益补充。在OOP中&#xff0c;万事万物都是独立的对象&#xff0c;对象相互耦合关系是基于业务进行的&#xff1b;但在…

【逗老师的PMP学习笔记】8、项目质量管理

目录 一、规划质量管理1、质量管理的发展历史2、戴明环&#xff0c;PDCA理论3、【关键输入】事业环境因素4、【关键输入】成本效益分析5、【关键工具】质量成本6、【关键输出】质量管理计划7、插一嘴&#xff0c;项目的三个标准8、【关键工具】质量测量指标 二、管理质量1、【关…

[OnWork.Tools]系列 06-屏幕水印

简介 屏幕水印功能主要是在开会分享屏幕的时候在屏幕上增加水印 水印使用 水印启用和颜色设置 水印文字和大小设置 水印间距,透明度,角度调整

保护电脑健康,这些维护技巧你Get了吗?

文章目录 1.界面环境1.1合理布置终端桌面1.2清理垃圾信息1.3关注运行环境和系统信息 2.程序管理2.1安装软件时需谨慎2.2及时更新软件和操作系统2.3合理管理插件和工具栏 3.网络防护3.1保护个人隐私3.2防范网络攻击3.3备份重要数据 4.电源管理4.1合理关机和电源设置4.2定期清理灰…

ESP32开发阶段启用 Secure Boot 与 Flash encryption

Secure Boot 与 Flash encryption详情 请参考&#xff1a;https://blog.csdn.net/espressif/article/details/79362094 1、开发环境 AT版本&#xff1a;2.4.0.0 发布IDF 与 python&#xff1a; idf4.3_py3.10_env系统&#xff1a;虚拟机 ubuntu 20 2、使能 secure boot 和 …

手搓 自然语言模型 LLM 拆分em结构设计 网络参数对比

数据 数据集 新的em编码参数表 voc_sizehidden_sizetotaltotal Bmax_lensecondsdays65536512374865920.03749B10242560.2655361024828375040.08284B20485120.5655362048<

yo!这里是STL::list类简单模拟实现

目录 前言 重要接口实现 框架 默认成员函数 迭代器&#xff08;重点&#xff09; 1.引言 2.list迭代器类实现 3.list类中调用实现 增删查改 后记 前言 我们知道&#xff0c;stl中的vector对应数据结构中的顺序表&#xff0c;string类对应字符串&#xff0c;而今天要…

Spring Data学习笔记Day01-SpringData入门

Spring Data基本介绍 目录 Spring Data Redis 官方API参考手册&#xff01;★ Spring Data的价值★ Spring Data及其子项目★ 强大的Spring Data★ Repository接口★ 具体Repository接口★ Spring Data JPA开发★ Spring Boot如何选择DataSource★ 数据源相关配置★ 配置第三方…

spring源码高级-图灵周瑜

实现factorybean可以产生代理对象

文件数字水印,附一种纯文本隐写术数字水印方法

数字水印&#xff08;Digital Watermark&#xff09;是一种在数字媒体文件中嵌入隐藏信息的技术。这些数字媒体可以是图片、音频、视频或文本等。数字水印不会对原始文件造成明显的视觉或听觉变化&#xff0c;但可以在一定程度上保护知识产权&#xff0c;追踪数据来源&#xff…

4个不是镜像但生成质量不输ChatGPT的其他AI聊天机器人

最近又发现其他几个类似ChatGPT的好用且质量还不错的AI聊天机器人&#xff0c;特意分享给大家。 Bing AI Bing AI工作原理与OpenAI的ChatGPT非常相似。Bing AI聊天机器人是利用ChatGPT的大语言模型&#xff0c;能够生成不同形式的内容&#xff0c;例如博客、文章、描述、诗歌等…

尚硅谷大数据项目《在线教育之采集系统》笔记004

视频地址&#xff1a;尚硅谷大数据项目《在线教育之采集系统》_哔哩哔哩_bilibili 目录 P047 P048 P049 P050 P051 P052 P053 P054 P055 P056 P047 /opt/module/datax/job/base_province.json [atguigunode001 ~]$ hadoop fs -mkdir /base_province/2022-02-22 [atgu…

动手学深度学习Pytorch 4.4练习

1.这个多项式回归问题可以准确地解出吗&#xff1f;提⽰&#xff1a;使⽤线性代数。 可以,把多项式问题&#xff0c;用matlab的str2sym表示出来&#xff0c;再用solve求解。 2.考虑多项式的模型选择。 1. 绘制训练损失与模型复杂度&#xff08;多项式的阶数&#xff09;的关系…

以太网收发及TSN概述

一、概述 TSN&#xff08;Time-Sensitive Networking&#xff09;时间敏感网络&#xff0c;即在非确定性的以太网中实现确定性的最小时间延时的协议族&#xff0c;是IEEE 802.1工作组中的TSN工作组开发的一套协议标准&#xff0c;定义了以太网数据传输的时间敏感机制&#xff…

探析青少年口才训练在个人发展中的重要性与影响

论文题目&#xff1a;探析青少年口才训练在个人发展中的重要性与影响 摘要&#xff1a; 本论文旨在探讨青少年口才训练对个人发展的重要性和影响。通过对相关文献的综述和实证研究的分析&#xff0c;论文将阐述口才训练对青少年自信心、表达能力和思维能力的提升&#xff0c;以…

常见分布式ID解决方案总结:数据库、算法、开源组件

常见分布式ID解决方案总结 分布式ID分布式ID方案之数据库数据库主键自增数据库号段模式Redis自增MongoDB 分布式ID方案之算法UUIDSnowflake(雪花算法) 雪花算法的使用IdWorker工具类配置分布式ID生成器 分布式ID方案之开源组件uid- generator(百度)Tinyid&#xff08;滴滴&…

Leetcode.1559 二维网格图中探测环

题目链接 Leetcode.1559 二维网格图中探测环 rating : 1838 题目描述 给你一个二维字符网格数组 g r i d grid grid &#xff0c;大小为 m x n &#xff0c;你需要检查 g r i d grid grid 中是否存在 相同值 形成的环。 一个环是一条开始和结束于同一个格子的长度 大于等于…

Java基础(四)

循环结构 1. while循环 循环变量初始化 while (循环条件){循环体; }循环条件是一个布尔类型的表达式&#xff0c;他的值为 true 时执行循环体&#xff0c;如果为 false 时终止循环体。while 循环是先判断条件是否成立&#xff0c;再决定是否执行循环体。如果第一次循环时&…

【APITable】教程:创建并运行一个自建小程序

1.进入APITable&#xff0c;在想要创建小程序的看板页面点击右上角的【小程序】&#xff0c;进入小程序编辑页面。 2.创建一个新的小程序区。 点击【 添加小程序】 点击创建小程序&#xff0c;选择模板&#xff0c;输入名字。 3.确定后进入小程序部署引导页面。 4.打开Xshell 7…

06-3_Qt 5.9 C++开发指南_多窗体应用程序的设计(主要的窗体类及其用途;窗体类重要特性设置;多窗口应用程序设计)

文章目录 1. 主要的窗体类及其用途2. 窗体类重要特性的设置2.1 setAttribute()函数2.2 setWindowFlags()函数2.3 setWindowState()函数2.4 setWindowModality()函数2.5 setWindowOpacity()函数 3. 多窗口应用程序设计3.1 主窗口设计3.2 QFormDoc类的设计3.3 QFormDoc类的使用3.…