【C++】AVLTree(AVL树)简单模拟

文章目录

  • 1.AVL树的结点
  • 2.AVL树的插入
  • 3.AVL树的旋转
    • 3.1 新节点插入较高左子树的左侧---左左:右单旋
    • 3.2 新节点插入较高右子树的右侧---右右:左单旋
    • 3.3 新节点插入较高左子树的右侧---左右:先左单旋再右单旋
    • 3.4 新节点插入较高右子树的左侧---右左:先右单旋再左单旋
  • 4.总代码

后续有时间会再更新erase

1.AVL树的结点

template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;std::pair<K, V> _kv;int _bf;  // balance factorAVLTreeNode(const std::pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}
};

2.AVL树的插入

	bool Insert(const std::pair<K, V>& kv){// 1. 先按照二叉搜索树的规则将节点插入到AVL树中// ...// 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,// 此时就需要更新平衡因子,并检测是否//破坏了AVL树 的平衡性/*Cur插入后,Parent的平衡因子一定需要调整,在插入之前,Parent的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:1. 如果Cur插入到Parent的左侧,只需给Parent的平衡因子-1即可2. 如果Cur插入到Parent的右侧,只需给Parent的平衡因子+1即可此时:Parent的平衡因子可能有三种情况:0,正负1, 正负21. 如果Parent的平衡因子为0,说明插入之前Parent的平衡因子为正负1,插入后被调整成0,此时满足AVL树的性质,插入成功2. 如果Parent的平衡因子为正负1,说明插入前Parent的平衡因子一定为0,插入后被更新成正负1,此时以Parent为根的树的高度增加,需要继续向上更新3. 如果Parent的平衡因子为正负2,则Parent的平衡因子违反平衡树的性质,需要对其进行旋转处理*/if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//...// 更新平衡因子while (parent){// 更新双亲的平衡因子if (cur == parent->_left)parent->_bf--;elseparent->_bf++;// 更新后检测双亲的平衡因子if (parent->_bf == 0) // 1 -1 -> 0{// 更新结束break;}else if (parent->_bf == 1 || parent->_bf == -1)  // 0 -> 1 -1{// 插入前双亲的平衡因子是0,插入后双亲的平衡因为为1 或者 -1 ,// 说明以双亲为根的二叉树的高度增加了一层,因此需要继续向上调整// 继续往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2) // 1 -1 -> 2 -2{// 双亲的平衡因子为正负2,违反了AVL树的平衡性,需要对以Parent// 为根的树进行旋转处理// 当前子树出问题了,需要旋转平衡一下if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){RotateL(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;}

3.AVL树的旋转

3.1 新节点插入较高左子树的左侧—左左:右单旋

	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;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}parent->_bf = subL->_bf = 0;}

3.2 新节点插入较高右子树的右侧—右右:左单旋

	void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;Node* ppNode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_right == parent){ppNode->_right = subR;}else{ppNode->_left = subR;}subR->_parent = ppNode;}parent->_bf = subR->_bf = 0;}

3.3 新节点插入较高左子树的右侧—左右:先左单旋再右单旋

	void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_bf = 0;}}

3.4 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

	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){subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subL->_bf = 0;parent->_bf = 0;}else{assert(false);}}

4.总代码

/*
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1 / 0 / 1)
*/
template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;std::pair<K, V> _kv;int _bf;  // balance factorAVLTreeNode(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:// logNbool Insert(const std::pair<K, V>& kv){// 1. 先按照二叉搜索树的规则将节点插入到AVL树中// ...// 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,// 此时就需要更新平衡因子,并检测是否//破坏了AVL树 的平衡性/*Cur插入后,Parent的平衡因子一定需要调整,在插入之前,Parent的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:1. 如果Cur插入到Parent的左侧,只需给Parent的平衡因子-1即可2. 如果Cur插入到Parent的右侧,只需给Parent的平衡因子+1即可此时:Parent的平衡因子可能有三种情况:0,正负1, 正负21. 如果Parent的平衡因子为0,说明插入之前Parent的平衡因子为正负1,插入后被调整成0,此时满足AVL树的性质,插入成功2. 如果Parent的平衡因子为正负1,说明插入前Parent的平衡因子一定为0,插入后被更新成正负1,此时以Parent为根的树的高度增加,需要继续向上更新3. 如果Parent的平衡因子为正负2,则Parent的平衡因子违反平衡树的性质,需要对其进行旋转处理*/if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//...// 更新平衡因子while (parent){// 更新双亲的平衡因子if (cur == parent->_left)parent->_bf--;elseparent->_bf++;// 更新后检测双亲的平衡因子if (parent->_bf == 0) // 1 -1 -> 0{// 更新结束break;}else if (parent->_bf == 1 || parent->_bf == -1)  // 0 -> 1 -1{// 插入前双亲的平衡因子是0,插入后双亲的平衡因为为1 或者 -1 ,// 说明以双亲为根的二叉树的高度增加了一层,因此需要继续向上调整// 继续往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2) // 1 -1 -> 2 -2{// 双亲的平衡因子为正负2,违反了AVL树的平衡性,需要对以Parent// 为根的树进行旋转处理// 当前子树出问题了,需要旋转平衡一下if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){RotateL(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;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return cur;}}return nullptr;}void InOrder(){_InOrder(_root);std::cout << std::endl;}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;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}parent->_bf = subL->_bf = 0;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;Node* ppNode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_right == parent){ppNode->_right = subR;}else{ppNode->_left = subR;}subR->_parent = ppNode;}parent->_bf = subR->_bf = 0;}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_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){subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subL->_bf = 0;parent->_bf = 0;}else{assert(false);}}bool IsBalance(){return _IsBalance(_root);}int Height(){return _Height(_root);}int Size(){return _Size(_root);}private:int _Size(Node* root){return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;}int _Height(Node* root){if (root == nullptr)return 0;return std::max(_Height(root->_left), _Height(root->_right)) + 1;}bool _IsBalance(Node* root){if (root == nullptr)return true;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 不平衡if (abs(leftHeight - rightHeight) >= 2){std::cout << root->_kv.first << std::endl;return false;}// 顺便检查一下平衡因子是否正确if (rightHeight - leftHeight != root->_bf){std::cout << root->_kv.first << std::endl;return false;}return _IsBalance(root->_left)&& _IsBalance(root->_right);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);std::cout << root->_kv.first << ":" << root->_kv.second << std::endl;_InOrder(root->_right);}
private:Node* _root = nullptr;
};

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

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

相关文章

零基础Vue入门6——Vue router

本节重点&#xff1a; 路由定义路由跳转 前面几节学习的都是单页面的功能&#xff08;都在专栏里面https://blog.csdn.net/zhanggongzichu/category_12883540.html&#xff09;&#xff0c;涉及到项目研发都是有很多页面的&#xff0c;这里就需要用到路由&#xff08;vue route…

【数据结构】(6) LinkedList 链表

一、什么是链表 1、链表与顺序表对比 不同点LinkedListArrayList物理存储上不连续连续随机访问效率O(N)O(1&#xff09;插入、删除效率O(1)O(N) 3、链表的分类 链表根据结构分类&#xff0c;可分为单向/双向、无头结点/有头节点、非循环/循环链表&#xff0c;这三组每组各取…

使用Pygame制作“俄罗斯方块”游戏

1. 前言 俄罗斯方块&#xff08;Tetris&#xff09; 是一款由方块下落、行消除等核心规则构成的经典益智游戏&#xff1a; 每次从屏幕顶部出现一个随机的方块&#xff08;由若干小方格组成&#xff09;&#xff0c;玩家可以左右移动或旋转该方块&#xff0c;让它合适地堆叠在…

(苍穹外卖)项目结构

苍穹外卖项目结构 后端工程基于 maven 进行项目构建&#xff0c;并且进行分模块开发。 1). 用 IDEA 打开初始工程&#xff0c;了解项目的整体结构&#xff1a; 对工程的每个模块作用说明&#xff1a; 序号名称说明1sky-take-outmaven父工程&#xff0c;统一管理依赖版本&…

【漫画机器学习】082.岭回归(或脊回归)中的α值(alpha in ridge regression)

岭回归&#xff08;Ridge Regression&#xff09;中的 α 值 岭回归&#xff08;Ridge Regression&#xff09;是一种 带有 L2​ 正则化 的线性回归方法&#xff0c;用于处理多重共线性&#xff08;Multicollinearity&#xff09;问题&#xff0c;提高模型的泛化能力。其中&am…

websocket自动重连封装

websocket自动重连封装 前端代码封装 import { ref, onUnmounted } from vue;interface WebSocketOptions {url: string;protocols?: string | string[];reconnectTimeout?: number; }class WebSocketService {private ws: WebSocket | null null;private callbacks: { [k…

【华为OD-E卷 - 115 数组组成的最小数字 100分(python、java、c++、js、c)】

【华为OD-E卷 - 数组组成的最小数字 100分&#xff08;python、java、c、js、c&#xff09;】 题目 给定一个整型数组&#xff0c;请从该数组中选择3个元素组成最小数字并输出 &#xff08;如果数组长度小于3&#xff0c;则选择数组中所有元素来组成最小数字&#xff09; 输…

在Vue3 + Vite 项目中使用 Tailwind CSS 4.0

文章目录 首先是我的package.json根据官网步骤VS Code安装插件验证是否引入成功参考资料 首先是我的package.json {"name": "aplumweb","private": true,"version": "0.0.0","type": "module","s…

AURIX TC275学习笔记4 官方GTM例程 GTM_TOM_PWM_1

文章目录 概述其他例程 代码分析IfxGtm_enable()IfxGtm_Cmu_enableClocks&#xff08;&#xff09;IfxGtm_Tom_Pwm_initConfig&#xff08;&#xff09;IfxGtm_Tom_Pwm_init&#xff08;&#xff09;IfxGtm_Tom_Pwm_start&#xff08;&#xff09;fadeLED() 概述 目的&#xf…

ASP.NET Core中间件的概念及基本使用

什么是中间件 中间件是ASP.NET Core的核心组件&#xff0c;MVC框架、响应缓存、身份验证、CORS、Swagger等都是内置中间件。 广义上来讲&#xff1a;Tomcat、WebLogic、Redis、IIS&#xff1b;狭义上来讲&#xff0c;ASP.NET Core中的中间件指ASP.NET Core中的一个组件。中间件…

app专项测试(网络测试流程)

一、网络测试的一般流程 step1&#xff1a;首先要考虑网络正常的情况 ① 各个模块的功能正常可用 ② 页面元素/数据显示正常 step2&#xff1a;其次要考虑无网络的情况 ① APP各个功能在无网络情况下是否可用 ② APP各个页面之间切换是否正常 ③ 发送网络请求时是…

Vue el-input密码输入框 按住显示密码,松开显示*;阻止浏览器密码回填,自写密码输入框;校验输入非汉字内容;文本框聚焦到内容末尾;

输入框功能集合 <template><div style"padding: 10px"><!-- 密码输入框 --><el-input:type"inputType"v-model"password"placeholder"请输入密码"auto-complete"new-password"id"pwd"style…

【数据结构】_复杂度

目录 1. 算法效率 2. 时间复杂度 2.1 时间复杂度概念 2.2 准确的时间复杂度函数式 2.3 大O渐进表示法 2.4 时间复杂度的常见量级 2.5 时间复杂度示例 3. 空间复杂度 3.1 空间复杂度概念 3.2 空间复杂度示例 1. 算法效率 一般情况下&#xff0c;衡量一个算法的好坏是…

Day48_20250130【回校继续打卡】_单调栈part1_739.每日温度|496.下一个更大元素I|503.下一个更大元素II

Day48_20250130_单调栈part1_739.每日温度|496.下一个更大元素I|503.下一个更大元素II 20250130补完 739.每日温度 题目 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0…

ASP.NET Core中间件Markdown转换器

目录 需求 文本编码检测 Markdown→HTML 注意 实现 需求 Markdown是一种文本格式&#xff1b;不被浏览器支持&#xff1b;编写一个在服务器端把Markdown转换为HTML的中间件。我们开发的中间件是构建在ASP.NET Core内置的StaticFiles中间件之上&#xff0c;并且在它之前运…

Text2Sql:开启自然语言与数据库交互新时代(3030)

一、Text2Sql 简介 在当今数字化时代&#xff0c;数据处理和分析的需求日益增长。对于众多非技术专业人员而言&#xff0c;数据库操作的复杂性常常成为他们获取所需信息的障碍。而 Text2Sql 技术的出现&#xff0c;为这一问题提供了有效的解决方案。 Text2Sql&#xff0c;即文…

将Deepseek接入pycharm 进行AI编程

目录 专栏导读1、进入Deepseek开放平台创建 API key 2、调用 API代码 3、成功4、补充说明多轮对话 总结 专栏导读 &#x1f338; 欢迎来到Python办公自动化专栏—Python处理办公问题&#xff0c;解放您的双手 &#x1f3f3;️‍&#x1f308; 博客主页&#xff1a;请点击——…

【人工智能】使用Python实现图像风格迁移:理论、算法与实践

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 图像风格迁移是一种利用深度学习技术将一张图像的内容与另一张图像的风格相结合的技术。本文将深入探讨图像风格迁移的基本理论和实现方法,…

ASP.NET Core筛选器Filter

目录 什么是Filter&#xff1f; Exception Filter 实现 注意 ActionFilter 注意 案例&#xff1a;自动启用事务的筛选器 事务的使用 TransactionScopeFilter的使用 什么是Filter&#xff1f; 切面编程机制&#xff0c;在ASP.NET Core特定的位置执行我们自定义的代码。…

缓存类为啥使用 unordered_map 而不是 map

性能考虑&#xff1a; std::unordered_map 是基于哈希表实现的&#xff0c;而 std::map 是基于红黑树实现的。对于查找操作&#xff0c;std::unordered_map 的平均查找时间复杂度是 O ( 1 ) O(1) O(1)&#xff0c;而 std::map 的查找时间复杂度是 O ( l o g n ) O(log n) O(l…