c++简单实现avl树

文章目录

  • AVL树
    • 节点类
      • 节点类的构造函数
    • AVL
      • insert()插入
        • RotateL(左单旋)
        • RotateR(右单旋)
        • RotateLR(右双旋)
        • RotateRL(左双旋)
      • Find(查找)
      • IsBalance(检查是否是avl树)

AVL树

AVL树:又名高度平衡树,在二叉搜索树的基础上加上了一个条件,条件是左右子树高度差不超过1
在这里插入图片描述

节点类

节点类:更好的管理节点
这里我选择的是右子树-左子树作为平衡因子,有平衡因子更方便实现

template<class K,class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf;//balance factor 平衡因子:右子树-左子树的值 不超过1pair<K, V> _kv;
};

节点类的构造函数

AVLTreeNode(const pair<K, V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0),_kv(kv){}

AVL

因为是高度平衡所以我们要一直控制他的高度,使其达到平衡

template<class K, class V>
class AVLTree
{
public:typedef AVLTreeNode<K, V> Node;
private:Node* _root;
};

insert()插入

插入规则:
1、按照搜索树的规则
2、更新平衡因子
3、更新因子规则 : c是p的左边 bf-- c是p的右边 ++
4、更新因子后, p的bf == 0 那么不会影响爷爷,说明更新前 p的bf为1 or -1 ,p的矮的那一边插入了节点.
如果更新后 p的bf == 1 or -1 那么就会影响爷爷.并且往上更新
更新后p的bf==2 那么旋转处理

	bool Insert(const pair<K,V>& kv){if (_root == nullptr)//树为空的情况{_root = new Node(kv);//直接做根节点return true;}Node* parent = nullptr;//因为cur是局部变量函数走完会销毁,所以增加一个指针 链接curNode* cur = _root;//赋值为根代替根操作while (cur){//插入的值的key值比较//大往右 小往左if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else//如果有这个值了返回false 因为avl树中不能有同样的值{return false;}}cur = new Node(kv);//new一个新节点赋值给curif (parent->_kv.first < kv.first)//大就链右边 小链左边{parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//让新节点指向其父节点//因为插入了//所以要修改parent的平衡因子while (parent){if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0)//更新 前为 1或者-1 更新后树就平衡了//结束{break;}else if (parent->_bf == 1 || parent->_bf - 1)//之前为 0 更新会影响祖先//继续往上{cur = cur->_parent;parent = parent->_parent;}else if (parent->_bf == 2 || 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)//左双旋{RotateRL(parent);}else if (parent->_bf == -2 && cur->_bf == 1)//右双旋{RotateLR(parent);}break;}else{assert(false);}}return true;
}
RotateL(左单旋)

以图来介绍
25是传过来的parent
我们定义parent的右为subR(也就是cur),定义cur的左为subRL(也就是cur->left)
我们旋转的时候把subRL给到parent的左边
然后把parent给到subR的左边
这样子就完成了左单旋
最后修改一下平衡因子就可以了

在这里插入图片描述

void RotateL(Node* parent)//左旋转
{//定义p的右边为 subR p的右节点的左节点为 subRL//subRL可能是一个子树的根节点Node* subR = parent->_right;//curNode* subRL = subR->_left;//cur->_left//把p的右边给  p的右边的左边 因为他一点比p大比p的右边小parent->_right = subRL;//把p的右边 链接p 让p的右边成为根if(subRL)//可能为空subRL->_parent = parent;subR->_left = parent;//保存一份p的父节点 因为原来的p要改父节点了Node* ppnode = parent->_parent;//p的父节点指向他原来的右子树parent->_parent = subR;//判断p是不是树根节点//如果是的话 让root改一下 他的父节点设置为空if (parent == _root){_root = subR;subR->_parent = nullptr;}else//如果不是树根节点{//如果原来的p是p父节点的左边 那么让他的左边链接现在的sub(原p右节点)if (ppnode->_left == parent){ppnode->_left = subR;}//如果是右边 那么同理else{ppnode->_right = subR;}subR->_parent = ppnode;}//最后改好后让他的平衡因子变一下 //因为已经平衡了所以p 的因子成为了0 subr 左右树高平衡了所以也要改成0parent->_bf = 0;subR->_bf = 0;
}
RotateR(右单旋)

以图来介绍
20是传过来的parent
我们定义parent的左为subL(也就是cur),定义cur的右为subLR(也就是cur->left)
我们旋转的时候把subRL给到parent的左边
然后把parent给到subL的右边
这样子就完成了右单旋
最后修改一下平衡因子就可以了

在这里插入图片描述

void RotateR(Node* parent)//右单旋
{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)//可能为空subLR->_parent = parent;subL->_right = parent;Node* ppnode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;subL->_parent = nullptr;}else//如果不是树根节点{if (ppnode->_left == parent){ppnode->_left = subL;}else{ppnode->_right = subL;}subL->_parent = ppnode;}parent->_bf = 0;subL->_bf = 0;
}
RotateLR(右双旋)

以图解释
右双旋就是先左单旋,后右单旋
对subL进行左单旋,获得图2
然后parent进行右单旋
获得图3
最后后平衡一下平平衡因子

在这里插入图片描述

void RotateLR(Node* parent)//先左单旋 后右单旋 右双旋
{Node* subL = parent->_left;Node* subLR = parent->_left->_right;RotateL(parent->_left);RotateR(parent);//用 _bf来查看是谁插入if (subLR->_bf == -1){//b位置插入subLR->_bf = 0;subL->_bf = 1;parent->_bf = 0;}else if (subLR->_bf == 1){//c位置插入subLR->_bf = 0;subL->_bf = -1;parent->_bf = 0;}else if (subLR->_bf == 0){//新增subLR->_bf = 0;subL->_bf = 0;parent->_bf = 0;}else{assert(false);}
}
RotateRL(左双旋)

以图解释
左双旋就是先右单旋,后左单旋
对subR进行右单旋,获得图2
然后对parent进行左单旋
获得图3
最后后平衡一下平平衡因子

在这里插入图片描述

Find(查找)

查找一个数
大了往左找,小了往右找

bool _Find(Node* _root,const K& x)
{if (_root == nullptr){return false;}if (_root->_kv.first == x){return true;}return _Find(_root->_left,x) || _Find(_root->_right,x);
}
bool Find(const K& x)
{return _Find(_root, x);
}

IsBalance(检查是否是avl树)

检查是否是AVL树
从规则入手

int _Height(Node* root)
{if (root == nullptr)return 0;return _Height(root->_left) + _Height(root->_right) + 1;
}
bool _IsBalance(Node* Root)
{// 空树也是AVL树if (nullptr == Root) return true;// 计算Root节点的平衡因子:即Root左右子树的高度差int leftHeight = _Height(Root->_left);int rightHeight = _Height(Root->_right);int diff = rightHeight - leftHeight;// 如果计算出的平衡因子与Root的平衡因子不相等,或者// Root平衡因子的绝对值超过1,则一定不是AVL树if (diff != Root->_bf || (diff > 1 || diff < -1))return false;// Root的左和右如果都是AVL树,则该树一定是AVL树return _IsBalance(Root->_left) && _IsBalance(Root -> _right);
}
bool IsBalance()
{_IsBalance(_root);
}

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

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

相关文章

vulhub中GitLab 远程命令执行漏洞复现(CVE-2021-22205)

GitLab是一款Ruby开发的Git项目管理平台。在11.9以后的GitLab中&#xff0c;因为使用了图片处理工具ExifTool而受到漏洞CVE-2021-22204的影响&#xff0c;攻击者可以通过一个未授权的接口上传一张恶意构造的图片&#xff0c;进而在GitLab服务器上执行任意命令。 环境启动后&am…

FFmpeg查看所有支持的编码/解码器/封装/解封装/媒体格式/滤镜

查看所有支持的编码器与解码器 ffmpeg -codecs 只查看所有编码器: ffmpeg -encoders 只查看所有解码器: ffmpeg -decoders 只查看H264编码器: ffmpeg -h encoderh264 只查看H264解码器: ffmpeg -h decoderh264 查看所有支持的封装: ffmpeg -muxers 查看所有支持的解封装…

【开源鸿蒙】为QEMU RISC-V虚拟平台构建OpenHarmony轻量系统

文章目录 一、背景介绍二、准备OpenHarmony源代码三、准备hb命令3.1 安装hb命令3.2 检查hb命令 四、编译RISC-V架构的OpenHarmony轻量系统4.1 设置hb构建目标4.2 启动hb构建过程 五、问题解决5.1 hb set 报错问题解决 六、参考链接 开源鸿蒙坚果派&#xff0c;学习鸿蒙一起来&a…

【每日算法】常见AIGC模型; 刷题:力扣单调栈

上期文章 【每日算法】理论&#xff1a;生成模型基础&#xff1b; 刷题&#xff1a;力扣单调栈 文章目录 上期文章一、上期问题二、理论问题1、stable diffusion模型的网络架构2、T5的网络架构&#xff08;Text-To-Text Transfer Transformer模型&#xff09;3、SDXL模型4、DA…

Git全套教程一套精通git.跟学黑马笔记

Git全套教程一套精通git.跟学黑马笔记 文章目录 Git全套教程一套精通git.跟学黑马笔记1.版本管理工具概念2. 版本管理工具介绍2.1版本管理发展简史(维基百科)2.1.1 SVN(SubVersion)2.1.2 Git 3. Git 发展简史4. Git 的安装4.1 git 的下载4.2 安装4.3 基本配置4.4 为常用指令配置…

【jeecgboot】微服务实战LISM

目录 一、服务解决方案-Spring Cloud Alibaba1.1选用原因&#xff08;基于Spring Cloud Alibaba的试用场景&#xff09;1.2 核心组件使用前期规划 部署 nacos部署 mino使用JavaFreemarker模板引擎&#xff0c;根据XML模板文件生成Word文档使用JavaFlowable 工作流引擎前端 -vue…

【C++中日期类的实现】

一路&#xff0c;一路&#xff0c;一路从泥泞到风景............................................................................................... 目录 前言 一、【什么是日期类】 二、【代码实现】 1.【Date.h】部分&#xff1a; 2.【Date.cpp】部分&#xff1a;…

通用的springboot web jar包执行脚本,释放端口并执行jar包

1、通用的springboot web jar包执行脚本&#xff0c;释放端口并执行jar包&#xff1a; #!/bin/bash set -eDATE$(date %Y%m%d%H%M) # 基础路径 BASE_PATH/data/yitu-projects/yitu-xzhq/sftp # 服务名称。同时约定部署服务的 jar 包名字也为它。 SERVER_NAMEyitu-server # 环境…

大模型语言系列-Agent

文章目录 前言一、Agent是什么&#xff1f;二、LLM Agent1.西部世界小镇Agent2.BabyAGI3.AutoGPT4.Voyager Agent 总结 前言 自2022年ChatGPT诞生以来&#xff0c;LLM获得了收获了大量关注和研究&#xff0c;但究其根本&#xff0c;技术还是要为应用服务&#xff0c;如何将LLM…

探索编程新纪元:Code GeeX、Copilot与通义灵码的智能辅助之旅

在人工智能技术日新月异的今天&#xff0c;编程领域的革新也正以前所未有的速度推进。新一代的编程辅助工具&#xff0c;如Code GeeX、Copilot和通义灵码&#xff0c;正在重塑开发者的工作流程&#xff0c;提升编程效率&#xff0c;并推动编程教育的普及。本文将深入探讨这三款…

Docker 镜像源配置

目录 一、 Docker 镜像源1.1 加速域名1.2 阿里云镜像源&#xff08;推荐&#xff09; 二、Docker 镜像源配置2.1 修改配置文件2.1.1 Docker Desktop 配置2.1.2 命令行配置 2.2 重启 Docker 服务2.2.1 Docker Desktop 重启2.2.2 命令行重启 2.3 检查是否配置成功 参考资料 一、 …

SpringCloudAlibaba系列之Seata实战

目录 环境准备 1.下载seata安装包 2.修改配置文件 3.准备seata所需配置文件 4.初始化seata所需数据库 5.运行seata 服务准备 分布式事务测试 环境准备 1.下载seata安装包 Seata-Server下载 | Apache Seata 本地环境我们选择稳定版的二进制下载。 下载之后解压到指定目录…

网络分层架构(七/四层协议)详解

OSI七层模型和TCP/IP四层模型 业内普遍的分层方式有两种&#xff1a;OSI七层模型 和TCP/IP四层模型。记忆则为 “应表会传网数物” 关于协议&#xff1a; ① OSI七层模型详解 结构名 功能 主要设备 应用层 是最靠近用户的OSI层。用户接口、应用程序。应用层向应用进程展示…

详解MySql索引

目录 一 、概念 二、使用场景 三、索引使用 四、索引存在问题 五、命中索引问题 六、索引执行原理 一 、概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。暂时可以理解成C语言的指针,文章后面详解 二、使用场景 数据量较大&#xff0c;且…

P1881 绳子对折

题目描述 FJ 有一个长度为 L&#xff08;1≤L≤10,000&#xff09;的绳子。这个绳子上有 N&#xff08;1≤N≤100&#xff09;个结&#xff0c;包括两个端点。FJ 想将绳子对折&#xff0c;并使较短一边的绳子上的结与较长一边绳子上的结完全重合&#xff0c;如图所示&#xff…

CleanMyMac X2024永久免费的强大的Mac清理工具

作为产品功能介绍专员&#xff0c;很高兴向您详细介绍CleanMyMac X这款强大的Mac清理工具。CleanMyMac X具有广泛的清理能力&#xff0c;支持多种文件类型的清理&#xff0c;让您的Mac始终保持最佳状态。 系统垃圾 CleanMyMac X能够深入系统内部&#xff0c;智能识别并清理各种…

MinGW64 windows gcc编译器安装

下载编译好的文件包 https://sourceforge.net/projects/mingw-w64/ 打开网址 界面左上方 点File 滚轮 滚到下面 点 红框 解压 配置path 环境变量

Vue3+TS+Vite 找不到模块“@/components/xxx/xxx”或其相应的类型声明

引入vue文件时文件是存在的&#xff0c;引入路径也是对的&#xff0c;报找不到模块&#xff0c;有一些解决方案是在tsconfig.json里面做一些配置&#xff0c;大家可以自行百度&#xff08;不知道是不是我百度的不对&#xff0c;我的没有解决&#xff09;还有一种是在项目根目录…

进程学习--02

在C语言中&#xff0c;一般使用fork函数开辟进程&#xff0c;这个函数开辟进程后会返回一个进程号&#xff0c;在子进程中会返回0&#xff0c;在父进程中会返回子进程的进程号。 int main(){int ret fork();if(ret<0){fprintf(stderr, "pid error");exit(-1);}e…

【Python编程基础】第一节.Python基本语法(上)

文章目录 前言⼀、Python介绍二、Python环境配置三、Pycharm 书写代码四、Python基本语法 4.1 print 函数的简单使用 4.2 注释 4.3 Python 代码中三种波浪线和 PEP8 4.4 在 cmd 终端中运⾏ Python 代码 4.5 变量 4.6 数据类型 4.7 类型转换…