map、set底层封装模拟实现(红黑树)

文章目录

    • 一、红黑树
      • 1.1红黑树的规则:
      • 1.2红黑树的插入操作
        • 1.2.1不需要旋转(如果叔叔存在且为红,这里的C表示孩子,P表示父亲,U表示叔叔,G表示祖父),包含四种情况,无论孩子在哪里,都是只需要改变叔叔和父亲的颜色为黑,祖父为红,然后向上继续走,C = G
        • 1.2.2需要旋转(左旋,右旋,左右双旋,右左双旋),叔叔不存在或者为黑
      • 1.2红黑树的插入代码
      • 1.3红黑树的整体框架
    • 二、map、set的底层封装
      • 2.1set的底层封装
      • 2.2map的底层封装
      • 2.3红黑树的底层封装

一、红黑树

相较于前面的AVL树,红黑树的优势是:旋转次数减少,效率提高了,同时还保留了AVL树的查找优势

1.1红黑树的规则:

1.每个节点不是红色就是黑色
2.红色节点的孩子一定是黑色节点
3.不能有连续的红色节点
4.每条路径(走到空为止)上的黑色节点数量相同
5.最短路径<=最长路径<=2
最短路径(当某条路径只有黑色节点,而另一条路径红色节点数量和黑色节点相同,那么最长路径就是最短路路径的两倍)

1.2红黑树的插入操作

1.2.1不需要旋转(如果叔叔存在且为红,这里的C表示孩子,P表示父亲,U表示叔叔,G表示祖父),包含四种情况,无论孩子在哪里,都是只需要改变叔叔和父亲的颜色为黑,祖父为红,然后向上继续走,C = G

在这里插入图片描述

1.2.2需要旋转(左旋,右旋,左右双旋,右左双旋),叔叔不存在或者为黑

右旋的情况(这里省略了C,P,U所连的节点)

在这里插入图片描述
左右双旋的情况(这里省略了C,P,U所连的节点)
在这里插入图片描述
下面两种情况省略

1.2红黑树的插入代码

	bool Insert(const pair<K, V>& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;while (cur){if (data.first > cur->_data.first){parent = cur;cur = cur->_right;}else if (data.first < cur->_data.first){parent = cur;cur = cur->_left;}elsereturn false;}cur = new Node(data);if (parent->_data.first > cur->_data.first)parent->_left = cur;elseparent->_right = cur;cur->_parent = parent;//判断父亲是否为红,为黑就不管while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED)//叔叔存在且为红{uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;//继续向上处理parent = cur->_parent;}else{if (cur == parent->_left){//叔叔为黑或者叔叔不存在RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;parent->_col = RED;}break;}}else{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;//继续向上处理parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}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 (ppnode == nullptr){_root = subR;_root->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subR;}else{ppnode->_right = subR;}subR->_parent = ppnode;}
}void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* ppnode = parent->_parent;subL->_right = 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;}
}

1.3红黑树的整体框架

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;//颜色定义
enum color
{RED,BLACK
};template<class K,class V>
struct RBTreeNode
{typedef RBTreeNode<K, V> Node;pair<K, V> _data;Node* _left;Node* _right;Node* _parent;color _col;//构造函数RBTreeNode(const pair<K, V>& data):_left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _data(data){}
};template<class K,class V>
class RBTree
{
public:typedef RBTreeNode<K, V> Node;bool Insert(const pair<K, V>& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;while (cur){if (data.first > cur->_data.first){parent = cur;cur = cur->_right;}else if (data.first < cur->_data.first){parent = cur;cur = cur->_left;}elsereturn false;}cur = new Node(data);if (parent->_data.first > cur->_data.first)parent->_left = cur;elseparent->_right = cur;cur->_parent = parent;//判断父亲是否为红,为黑就不管while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED)//叔叔存在且为红{uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;//继续向上处理parent = cur->_parent;}else{if (cur == parent->_left){//叔叔为黑或者叔叔不存在RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;parent->_col = RED;}break;}}else{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;//继续向上处理parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}void Inorder(){_Inorder(_root);}private:void _Inorder(Node* root){if (root == nullptr)return;_Inorder(root->_left);cout << root->_data.first << endl;_Inorder(root->_right);}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 (ppnode == nullptr){_root = subR;_root->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subR;}else{ppnode->_right = subR;}subR->_parent = ppnode;}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* ppnode = parent->_parent;subL->_right = 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;}}Node* _root = nullptr;
};

二、map、set的底层封装

这里我们需要加上迭代器和仿函数(为了套用同一个红黑树的模版)
map有两个模版参数、set只有一个模版参数,因此我们需要加一个仿函数来确定是map还是set

2.1set的底层封装

namespace SF
{//仿函数template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K,const K, SetKeyOfT>::iterator iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}bool insert(const K& key){return _t.Insert(key);}private:RBTree<K,const K, SetKeyOfT> _t;};
}

2.2map的底层封装

namespace SF
{template<class K,class V> class map{struct MapKeyOfT{const K& operator()(const pair<K,V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}bool insert(const pair<K,V>& data){return _t.Insert(data);}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};
}

2.3红黑树的底层封装

#pragma once
#include<vector>enum Colour
{RED,BLACK
};template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;T _data;RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _col(RED){}
};template<class T>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T> Self;Node* _node;RBTreeIterator(Node* node):_node(node){}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}Self& operator++(){if (_node->_right){// 右子树的中序第一个(最左节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else{// 祖先里面孩子是父亲左的那个Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self& operator--(){// return *this;}bool operator!=(const Self& s){return _node != s._node;}bool operator== (const Self & s){return _node == s._node;}
};// set->RBTree<K, K, SetKeyOfT>
// map->RBTree<K, pair<K, V>, MapKeyOfT>// KeyOfT仿函数 取出T对象中的key
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef RBTreeIterator<T> iterator;iterator begin(){Node* subLeft = _root;while (subLeft && subLeft->_left){subLeft = subLeft->_left;}return iterator(subLeft);}iterator end(){return iterator(nullptr);}bool Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(data); // 红色的if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;// 情况一:叔叔存在且为红if (uncle && uncle->_col == RED){// 变色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续往上处理cur = grandfather;parent = cur->_parent;}else{// 情况二:叔叔不存在或者存在且为黑// 旋转+变色if (cur == parent->_left){//       g//    p    u// cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//       g//    p     u//      cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{Node* uncle = grandfather->_left;// 情况一:叔叔存在且为红if (uncle && uncle->_col == RED){// 变色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续往上处理cur = grandfather;parent = cur->_parent;}else{// 情况二:叔叔不存在或者存在且为黑// 旋转+变色//      g//   u     p//            cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//		g//   u     p//      cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}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;subR->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subR;}else{ppnode->_right = subR;}subR->_parent = ppnode;}}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;}}private:Node* _root = nullptr;
};

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

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

相关文章

对XYctf的一些总结

对XYctf的一些总结 WEB 1.http请求头字段 此次比赛中出现的&#xff1a; X-Forwarded-For/Client-ip&#xff1a;修改来源ip via&#xff1a;修改代理服务器 还有一些常见的字段&#xff1a; GET&#xff1a;此方法用于请求指定的资源。GET请求应该安全且幂等&#xff0c…

202003青少年软件编程(Python)等级考试试卷(二级)

第 1 题 【单选题】 运行下方代码段,输出的结果是(   )。 a=(1,2,3)print(type(a))A :<class ‘float’> B :<class ‘int’> C :<class ‘str’> D :<class ‘tuple’> 正确答案:D 试题解析: 第 2 题 【单选题】 content.txt中原来的内容…

企业想做新媒体矩阵怎么做?百家号,公众号,视频号,抖音,小红书等通用搞流量玩法参考

前言&#xff1a;这是白杨SEO原创第528篇。为什么想到写这个&#xff1f;因为很多企业或个人不知道在平台搞流量除了质量&#xff0c;还有一种方法就是人海战术&#xff0c;用数量取胜。今天简单分享一下&#xff0c;也许会给你启发&#xff0c;仅供参考。 分享大纲&#xff1…

雷军-2022.8小米创业思考-5-选择大于努力;倒在黎明前;互联网思维

第五章 我对互联网思维的理解 我的科技职业生涯起源于金山。金山作为一家老牌软件公司&#xff0c;在互联网时代似乎有些跟不上节奏。早年的金山也曾做过两次互联网转型。第一次是1999年年初成立卓越事业部&#xff0c;开始互联网业务尝试&#xff0c;后来又拆分成立卓越网。第…

“前人种树,后人乘凉”:【薪象营】五一探访活动弘扬传统美德

在五一劳动节这一天&#xff0c;唐刚携带【唐江军】的前成员&#xff0c;前往广州开展了一场特殊的慈善探访活动。这不仅是一个简单的慈善活动&#xff0c;更是唐刚希望向新成立的【薪象营】传承的一种精神和行动典范。 精神传承与实际行动 唐刚&#xff0c;【唐江军】的发起人…

3D模型实时变形算法

最近&#xff0c;在尝试渲染一些奇怪的形状后&#xff0c;我陷入了计算机图形学的困境。事实证明&#xff0c;对于我试图解决的具体问题&#xff0c;没有现有的选项完全适合我想要做的事情。几周后&#xff0c;我终于带着一些答案再次浮出水面&#xff0c;写了很多行代码&#…

webpack4和webpack5区别1---loader

webpack4处理图片和字体的loader file-loader file-loader的作用是处理webpack中的静态资源文件。File Loader可以将各种类型的文件&#xff0c;如图像、字体、视频等转换为模块并加载到Web应用程序中。它通过import或require语句引入文件资源&#xff0c;并将其放置在输出目…

​​【收录 Hello 算法】3.5 小结

目录 3.5 小结 1. 重点回顾 2. Q & A 3.5 小结 1. 重点回顾 数据结构可以从逻辑结构和物理结构两个角度进行分类。逻辑结构描述了数据元素之间的逻辑关系&#xff0c;而物理结构描述了数据在计算机内存中的存储方式。常见的逻辑结构包括线性、树状和网状等。…

【蓝桥杯备赛国赛】5-5

文章目录 求阶乘双子数 求阶乘 求阶乘 分析k的范围&#xff0c;10的18次方。这个数字很大 想要末尾有0的存在必须要2和5&#xff0c;但是通过分析2的数目应该是远远多于5的&#xff0c;所以只要5的数目够多即可。所以for循环的层次也是10的九次方以上&#xff0c;必然会超时&…

优雅处理返回信息状态码:Result对象在Spring Boot中的应用

前言 在开发过程中&#xff0c;处理返回的信息状态码是一个重要的问题&#xff0c;尤其是在大型项目中。为了统一处理这些状态码&#xff0c;我在Spring Boot中创建了一个名为Result的Java对象&#xff0c;用于封装返回的信息和状态码。在本文中&#xff0c;我将分享如何实现这…

面试经典150题——判断子序列

面试经典150题 day26 题目来源我的题解方法一 双指针方法二 动态规划 题目来源 力扣每日一题&#xff1b;题序&#xff1a;392 我的题解 方法一 双指针 分别使用一个指针控制两个字符串的遍历&#xff0c;当两个指针的位置的字符相同时&#xff0c;同时移动两个指针&#xf…

【信息系统项目管理师知识点速记】资源管理:规划资源管理

13.3 规划资源管理 定义&#xff1a; 规划资源管理是定义如何估算、获取、管理和利用团队以及实物资源的过程。 作用&#xff1a; 确定适用于项目资源的管理方法和管理程度。 输入&#xff1a; 项目章程项目管理计划 质量管理计划范围基准项目文件 需求文件项目进度计划风险…

python基础---垃圾回收

垃圾回收 Python的机制 小整数对象池 Python为了优化速度使用了小整数对象池, 避免整数频繁申请和销毁 Python的[-5, 256]这些整数的对象提前建立好了, 不会被垃圾回收, 在Python里面所有的这一些数据实际使用的是同一个对象, 单个的字母也是这样的 如果是一个字符串, 这一…

【算法系列】链表

目录 常用技巧 常用操作 leetcode/牛客题目 一、移除链表元素 二、反转链表 三、链表的中间结点 四、返回倒数第k个节点 五、合并两个有序链表 六、链表分割 七、链表的回文结构 八、相交链表 九、环形链表 十、环形链表 II 十一、随机链表的复制 十二、两数相加…

【图像增强(空域)】基于灰度变换的图像增强及Matlab仿真

1. 摘要&#xff1a; 空域内的图像增强就是调整灰度图像的明暗对比度&#xff0c;对图像中各个像素的灰度值直接进行处理。常用的方法包括&#xff1a;灰度变换增强和直方图增强。 2. 原理&#xff1a; 灰度变换增强是空域ne对图像进行增强的一种简单且直接的方法。灰度变换…

K8S Redis-Cluster安装(含redis-cluster-proxy、RedisInsight)

参考&#xff1a;在 K8S 中快速部署 Redis Cluster & Redisinsight 参考&#xff1a;Redis 中文文档&#xff08;一&#xff09; helm redis-cluster [rootk8s-master01 redis-cluster]# helm search repo redis-cluster NAME CHART VERSION APP …

使用CUDA的PyTorch进行张量重整化的gpu加速

使用CUDA的PyTorch进行张量重整化的gpu加速 摘要IntroductionAlgorithm and TorchTrg discussionModels and Results GPU-Acceleration of Tensor Renormalization with PyTorch using CUDA 摘要 作者展示了基于张量重整化群&#xff08;TRG&#xff09;方法的数值计算可以通过…

绝地求生:季后赛名额确定!NH战队总积分榜排名第一!

2024年5月5日&#xff0c;PCL春季赛常规赛第五阶段第三天比赛结束&#xff0c;今天打完春季赛常规赛结束&#xff0c;16个战队进入季后赛的名额已确定。NH战队总积分506分&#xff0c;总积分榜排名第一&#xff01;&#xff01;NH战队也是唯一一支总积分超过500分的队伍。今天最…

【前端】HTML实现个人简历信息填写页面

文章目录 前言一、综合案例&#xff1a;个人简历信息填写页面 前言 这篇博客仅仅是对HTML的基本结构进行了一些说明&#xff0c;关于HTML的更多讲解以及CSS、Javascript部分的讲解可以关注一下下面的专栏&#xff0c;会持续更新的。 链接&#xff1a; Web前端学习专栏 下面我对…

LLaMA 羊驼系大语言模型的前世今生

关于 LLaMA LLaMA是由Meta AI发布的大语言系列模型&#xff0c;完整的名字是Large Language Model Meta AI&#xff0c;直译&#xff1a;大语言模型元AI。Llama这个单词本身是指美洲大羊驼&#xff0c;所以社区也将这个系列的模型昵称为羊驼系模型。 Llama、Llama2 和 Llama3…