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…

[C++ 从入门到精通] 20.对象移动、移动构造函数、移动赋值运算符

📢博客主页:https://loewen.blog.csdn.net📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢本文由 丶布布原创,首发于 CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览: 一. 对象移动的概念二. 移动构造函数和移动赋值…

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…

SpringBoot中的HttpServletRequest

1.HttpServletRequest javax.servlet.http.HttpServletRequest是SUN制定的Servlet规范&#xff0c;是一个接口&#xff0c;表示请求&#xff0c; 其父接口是 javax.servlet.ServletRequest。“ HTTP 请求协议”的完整内容都被封装到 request对象中。 2.HttpServletRequest的生…

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

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

面试经典-32-判断子序列

题目 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde"的一个子序列…

【图像生成】(四) Diffusion原理 pytorch代码实例

之前介绍完了图像生成网络GAN和VAE&#xff0c;终于来到了Diffusion。stable diffusion里比较复杂&#xff0c;同时用到了diffusion&#xff0c;VAE&#xff0c;CLIP等模型&#xff0c;这里我们主要着重介绍diffusion网络本身。 2.原理 Diffusion扩散模型从字面上来理解&#…

通用的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 # 环境…

C++从零开始(day52)——unordered_set,unordered_map学习使用

1.unordered系列关联式容器 C98中&#xff0c;STL提供了底层为红黑树结构的一系列容器&#xff0c;在查找时效率可以达到时间复杂度可以达到O(logN)&#xff0c;即红黑树的高度次&#xff0c;当树中的结点非常多时&#xff0c;查询效率也不理想&#xff0c;因此在C11中&#x…

代码随想录算法训练营第11天|20.有效的括号 1047.删除字符串中的所有相邻重复项

20.有效的括号 栈类的题目都很神奇&#xff0c;这道题分有不有效有三种情况&#xff0c;一种是左括号多了&#xff0c;一种是右括号多了&#xff0c;一种是左括号和右括号不匹配。我们设置一个栈来放s[i]所对应的右括号&#xff0c;如果s[i]‘{’&#xff0c;那么就在栈里放‘}…

大模型语言系列-Agent

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

Lua中文语言编程源码-第五节,更改lcorolib.c协程库函数, 使Lua加载中文库关键词(与所有的基础库相关)

源码已经更新在CSDN的码库里&#xff1a; git clone https://gitcode.com/funsion/CLua.git 在src文件夹下的lcorolib.c协程库函数&#xff0c;Coroutine Library&#xff1a;表明这个C源文件实现了Lua的协程库&#xff08;Coroutine Library&#xff09;&#xff0c;即提供了…

探索编程新纪元: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 检查是否配置成功 参考资料 一、 …

kubernetes-pod的调度

kubernetes-pod的调度 kubernetes-71、pod停止之后&#xff0c;服务不会停止2、pod endpoint service之间的关系3、pod的调度总述1. 资源请求&#xff08;Resource Requests&#xff09;和资源限制&#xff08;Resource Limits&#xff09;2. 节点选择器&#xff08;Node Selec…

Android 卸载系统自带APP

https://www.xda-developers.com/uninstall-carrier-oem-bloatware-without-root-access/ pm uninstall -k --user 0 NameOfPackage pm install-existing NameOfPackage you can simply use “adb shell cmd package install-existing ” in ADB and you’ll get the package…