map和set的简易封装(纯代码)

RBTree.h

#pragma once#include<iostream>
#include<vector>
using namespace std;enum colar
{   red,black
};template<class T>//有效参数就一个 
struct RBTreeNode
{RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _co(red){}RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;colar _co;};template<class T,class ref,class ptr>
struct _Tree_iterator
{typedef RBTreeNode<T> Node;typedef _Tree_iterator<T,ref,ptr> self;Node* _cur;_Tree_iterator(Node* tmp):_cur(tmp){}self& operator++(){//将当前节点看作父节点再分析if (_cur->_right == nullptr)//向上返回(前提是父的左孩子)如果是右孩子则表明父亲已经遍历过了{Node* parent = _cur->_parent;while (parent && parent->_right == _cur)//parent可能为空{_cur = parent;parent = _cur->_parent;}//指向parent指向的left等于_cur 或者parent为空(遍历结束)_cur = parent;}else//自己就属于父节点,找右子树的最左节点{Node* tmp = _cur->_right;while (tmp->_left)//tmp不可能为空{tmp = tmp->_left;}_cur = tmp;}return *this;}self& operator--()//相较于operator++而言就是 右子树 根 左子树 的遍历方式{if (_cur->_left == nullptr)//表明当前节点遍历完成,向上返回……{Node* parent = _cur->_parent;while (parent&&parent->_left == _cur){_cur = parent;parent = parent->_parent;}_cur = parent;}else{//找左子树的最右节点_cur = _cur->_left;while (_cur->_right){_cur = _cur->_right;}}return *this;}ref operator*(){return _cur->_data;}ptr operator->(){return &_cur->_data;}bool operator!=(const self& tmp){return _cur != tmp._cur;}
};template<class K, class T,class Com_T>
class RBTree
{typedef RBTreeNode<T> Node;public:typedef _Tree_iterator<T,T&,T*> iterator;typedef _Tree_iterator<T,const T&,const T*> const_iterator;iterator begin(){Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return iterator(cur);}iterator end(){return iterator(nullptr);}const_iterator cbegin()const{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return const_iterator(cur);}const_iterator cend()const {return const_iterator(nullptr);}//pair <iterator, bool> insert(const T& data)//data类型取决于T,而T又取决于map和setpair <Node*, bool> insert(const T& data)//data类型取决于T,而T又取决于map和set{Node* newroot = new Node(data);//默认为红if (_root == nullptr){_root = newroot;_root->_co = black;//设为黑return make_pair(newroot,true);}Node* parent = _root, * cur = _root;//插入数据Com_T com;while (1){parent = cur;if (com(cur->_data) > com(data))//这里data的类型可能是pair(不确定){cur = cur->_left;if (cur == nullptr){parent->_left = newroot;newroot->_parent = parent;break;}}else if (com(cur->_data) < com(data)){cur = cur->_right;if (cur == nullptr){parent->_right = newroot;newroot->_parent = parent;break;}}else{return make_pair(cur, false);//数据相同返回相同数据的迭代器(类似是查找数据)}}//父节点的判断cur = newroot;//当前节点就是新插入的节点while (parent && parent->_co == red)//父亲节点可能不存在{Node* pparent = parent->_parent;//parent为红,不可能是根,一定存在pparentNode* uncle = nullptr;//找叔叔节点if (pparent->_right == parent)uncle = parent->_parent->_left;elseuncle = parent->_parent->_right;if (uncle && uncle->_co == red)//叔叔存在且为红{//变色parent->_co = uncle->_co = black;pparent->_co = red;//祖父节点有可能是根节点//继续向上更新处理cur = pparent;parent = cur->_parent;}else//叔叔节点为空或为黑{//旋转if (pparent->_left == parent && parent->_left == cur){//右单旋RotateR(pparent);parent->_co = black;pparent->_co = red;}else if (pparent->_right == parent && parent->_right == cur){//左单旋RotateL(pparent);parent->_co = black;pparent->_co = red;}else if (pparent->_right == parent && parent->_left == cur){//右左双旋RotateR(parent);RotateL(pparent);cur->_co = black;pparent->_co = red;}else if (pparent->_left == parent && parent->_right == cur){//左右双旋RotateL(parent);RotateR(pparent);cur->_co = black;pparent->_co = red;}break;//旋转之后新的根节点都是黑色}}_root->_co = black;//循环体内很有可能将根节点改为红return make_pair(newroot, true);}void RotateL(Node* parent)//左单旋{Node* cur = parent->_right;Node* curl = cur->_left;Node* pparent = parent->_parent;//提前记录parent->_right = curl;if (curl){curl->_parent = parent;}cur->_left = parent;parent->_parent = cur;//处理pparent与parent的连接if (_root == parent){_root = cur;cur->_parent = nullptr;}else{if (pparent->_left == parent)pparent->_left = cur;elsepparent->_right = cur;cur->_parent = pparent;}}void RotateR(Node* parent)//右单旋{{Node* cur = parent->_left;Node* curr = cur->_right;Node* pparent = parent->_parent;//提前记录parent->_left = curr;if (curr){curr->_parent = parent;}cur->_right = parent;parent->_parent = cur;//处理pparent与parent的连接if (_root == parent){_root = cur;cur->_parent = nullptr;}else{if (pparent->_left == parent)pparent->_left = cur;elsepparent->_right = cur;cur->_parent = pparent;}}}void InOrder(){_InOrder(_root);cout << endl;}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}// 根节点->当前节点这条路径的黑色节点的数量bool Check(Node* cur, int blacknum, int ref_val){if (cur == nullptr){if (blacknum == ref_val)return true;cout << "每条路径的黑色节点个数不同" << endl;return false;}Node* parent = cur->_parent;if (cur->_co == red && parent->_co == red)//向上判断,向下判断的节点可能为空或其它的。return false;if (cur->_co == black)blacknum++;return Check(cur->_left, blacknum, ref_val) && Check(cur->_right, blacknum, ref_val);}bool Is_balance(){if (_root->_co == red)return false;if (_root == nullptr)return true;//不能出现连续红节点//每条路径黑色节点要保证相同int blacknum = 0;//必须传值,相当于是每个节点都有一个变量表示从根到当前的黑节点个数int ref_val = 0;//参考值,求出任意一条路径中黑色节点数目Node* cur = _root;while (cur){if (cur->_co == black)ref_val++;cur = cur->_left;}return Check(_root, blacknum, ref_val);}private:Node* _root=nullptr;
};

Set.h

#include"RBTree.h"template<class  key>
class set
{
public:struct setCom//仿函数{const key& operator()(const key& k){return k;}};//typedef _Tree_iterator<key> iterator;typedef typename RBTree<key, key, setCom>::const_iterator iterator;typedef typename RBTree<key, key, setCom>::const_iterator const_iterator;//对类模版取内嵌类型,加typename是为了告诉编译器这里是类型pair<iterator,bool> insert(const key& k)//此时pair的第一个参数类型是const_iterator{return _s.insert(k);//insert返回pair<Node*,bool>会构造出pair<iterator,bool>}iterator begin()const{return _s.cbegin();}iterator end()const{return _s.cend();}private:RBTree<key, key, setCom> _s;//封装红黑树
};

Map.h

#include"RBTree.h"template<class  key,class val>
class map
{
public:struct mapCom//仿函数{const key& operator()(const pair<key,val>& p){return p.first;}}; //typedef _Tree_iterator<pair<key,val>> iterator;typedef typename RBTree<key, pair<const key, val>, mapCom>::iterator iterator;typedef typename RBTree<key, pair<const key, val>, mapCom>::const_iterator const_iterator;//对类模版取内嵌类型,加typename是为了告诉编译器这里是类型pair<iterator, bool> insert(const pair<key, val>& kv){return _m.insert(kv);}iterator begin(){return _m.begin();}iterator end(){return _m.end();}const_iterator cbegin()const{return _m.cbegin();}const_iterator cend()const{return _m.cend();}val& operator[](const key& k){pair<key, val> tmp(k, val());//val给缺省值,tmp是创建变量pair<iterator,bool> ret = insert(tmp);//返回插入的节点的pairreturn (ret.first)->second;}private: RBTree<key, pair<const key, val>,mapCom> _m;//封装红黑树(参数类型决定着红黑树的数据类型)
};  

test.cpp(测试)

#include"Map.h"
#include"Set.h"
#include<string>void test_set()
{set<int> s;s.insert(4);s.insert(1);s.insert(2);s.insert(3);s.insert(2);s.insert(0);s.insert(10);s.insert(5);set<int>::iterator it = s.begin();//浅拷贝while (it != s.end()){cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;
}void test_map()
{map<string, string> dict;dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("sort", "xx"));dict.insert(make_pair("left", "左边"));dict.insert(make_pair("right", "右边"));map<string, string>::const_iterator it = dict.cbegin();while (it != dict.cend()){cout << it->first << ":" << it->second << endl;++it;}cout << endl;string arr[] = { "㽶", "香蕉","ƻ", "香蕉", "ƻ", "香蕉", "ƻ", "ƻ", "香蕉", "ƻ", "㽶", "ƻ", "㽶" };map<string, int> countMap;for (auto& e : arr){countMap[e]++;}for (auto kv : countMap){cout << kv.first << ":" << kv.second << endl;}cout << endl;
}int main()
{//test_set();test_map();return 0;
}

如有问题欢迎留言!!!

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

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

相关文章

黑马点评回顾 redis实现共享session

文章目录 传统session缺点整体访问流程代码实现生成验证码登录 问题具体思路 传统session缺点 传统单体项目一般是把session存入tomcat&#xff0c;但是每个tomcat中都有一份属于自己的session,假设用户第一次访问第一台tomcat&#xff0c;并且把自己的信息存放到第一台服务器…

免费的快速手机文件解压APP,快冲

各位小伙伴们大家好&#xff0c;今天我要介绍一款手机上必备的神奇工具&#xff01;你有没有经常遇到需要解压文件情况呢&#xff1f;还在为不知道用哪个软件而烦恼吗&#xff1f;别担心&#xff0c;我给你带来了解决方案 &#xff0c;就是这一款免费的解压精灵。 解压精灵是一…

【Nginx】使用nginx进行反向代理与负载均衡

使用场景 反向代理&#xff1a;一个网站由许多服务器承载的&#xff0c;网站只暴露一个域名&#xff0c;那么这个域名指向一个代理服务器ip&#xff0c;然后由这台代理服务器转发请求到网站负载的多台服务器中的一台处理。这就需要用到Nginx的反向代理实现了 负载均衡&#xf…

怎么去掉邮件内容中的回车符

上图是Outlook 截图&#xff0c;可见1指向的总有回车符&#xff1b; 故障原因&#xff1a; 不小心误按了箭头4这个选项&#xff1b; 解决方法&#xff1a; 点击2箭头确保tab展开&#xff1b; 点击3以找到箭头4. 取消勾选或者多次点击&#xff0c;即可解决。

单区域OSPF配置

配置命令步骤&#xff1a; 1.使用router ospf 进程ID编号 启用OSPF路由 2.使用network 直连网络地址 反掩码 area 0 将其归于区域0 注意&#xff1a;1.进程ID编号可任意&#xff08;1-65535&#xff09;2.反掩码用4个255相减得到 如下图&#xff0c;根据给出要求配置OSPF单区…

HT8313 D/AB切换 音频功率放大器

HT8313具有AB类和D类的自Y切换功能&#xff0c;在受到D类功放EMI干扰困扰时&#xff0c;可随时切换至AB类音频功放模式&#xff08;此时电荷泵升压功能关闭&#xff09;。 HT8313内部固定28dB增益&#xff0c;内置的关断功能使待机电流Z小化&#xff0c;还集成了输出端过流保护…

JavaEE进阶学习:Spring核心和设计思想

Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃而庞大的社区&#xff0c;这就是它之所以能长久不衰的原因。Spring 支持广泛的应用场景&#xff0c;它可以让 Java 企业级…

PP-ChatOCRv2、PP-TSv2、大模型半监督学习工具...PaddleX新特性等你来pick!

小A是一名刚刚毕业的算法工程师&#xff0c;有一天&#xff0c;他被老板安排了一个活&#xff0c;要对一批合同扫描件进行自动化信息抽取&#xff0c;输出结构化的分析报表。OCR问题不大&#xff0c;但是怎么进行批量的结构化信息抽取呢&#xff1f;小A陷入了苦苦思索… 小B是…

Java获取Jar、War包路径,并生成可编辑修改的本地配置文件

前言 本地的可修改配置文件的编写理应是一个很常用的功能&#xff0c;但由于数据库的存在&#xff0c;它鲜少被提及&#xff0c;大多数我们直接存储到数据库中了。 以至于现今&#xff0c;除了没接触数据库的新手时常使用它以外&#xff0c;它没有太多的出场机会。 也因此&am…

Hive数据表操作--学习笔记

1&#xff0c;Hive数据表操作 1&#xff0c;建表语句和内外部表 ①创建内部表 create [external] table [if not exists] 表名( 字段名 字段类型 [comment 注释], 字段名 字段类型 [comment 注释], ... ) [row format delimited fields terminated by 指定分隔符];&#xff0…

后端接口性能优化分析-问题发现问题定义

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&…

使用requests库设置no_proxy选项的方法

问题背景 在使用requests库进行HTTP请求时&#xff0c;如果需要使用爬虫IP服务器&#xff0c;可以通过设置proxies参数来实现。proxies参数是一个字典&#xff0c;其中包含了爬虫IP服务器的地址和端口号。然而&#xff0c;当前的requests库并不支持通过proxies参数来设置no_pr…

【GitLab】-HTTP 500 curl 22 The requested URL returned error: 500~SSH解决

写在前面 本文主要介绍通过SSH的方式拉取GitLab代码。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.生成秘钥3.GitLab添加秘钥4.验证SSH方式4.更改原有HTTP方式为SSH 三、参考资料写在后面系列文章 一、场景描述 之前笔者是通过 HTTP Personal access token 的方式拉取…

持续集成指南:GitHubAction 自动构建+部署AspNetCore项目

前言 之前研究了使用 GitHub Action 自动构建和发布 nuget 包&#xff1a;开发现代化的.NetCore控制台程序&#xff1a;(4)使用GithubAction自动构建以及发布nuget包 现在更进一步&#xff0c;使用 GitHub Action 在其提供的 runner 里构建 docker 镜像&#xff0c;之后提交到阿…

6块钱改变世界,网易和拼多多踏入同一条河流?

年底将至&#xff0c;各种颁奖盛典星光熠熠。如果要给今年深蹲反弹中的互联网大厂颁奖&#xff0c;2023表现最突出的可能是师出同门的兄弟网易和拼多多。 从市场表现来看&#xff0c;两家企业录得今年互联网中概股最高涨幅&#xff0c;被称为“中概股之光”&#xff1a;2023年…

【Spring Cloud】黑马头条 用户服务创建、登录功能实现

点击去看上一篇 一、创建用户 model 1.创建用户数据库库 leadnews_user 核心表 ap_user 建库建表语句 这里一定要使用 navicat&#xff0c;执行SQL 文件&#xff0c;以防止 cmd 中的编码问题 先将 SQL 语句&#xff0c;保存在电脑中&#xff0c;再使用 navicat 打开 CREATE…

华为eNSP综合实验考试

VLAN信息表 设备名称 端口 链路类型 VLAN 参数 HZ-HZCampus-Agg01-S5731 GE0/0/1 Trunk PVID:1 Allow-pass&#xff1a;10 20 Eth-trunk1&#xff08;GE0/0/2,0/0/3,0/0/23&#xff09; Trunk PVID:1 Allow-pass&#xff1a;10 20 GE0/0/24 Access PVID&#xf…

(免费)双相情感障碍筛查MDQ 在线测试双向情感障碍

MDQ用于筛查双相障碍&#xff0c;主要包含13个关于双相障碍症状的是非问题&#xff0c;当前测试采用的量表为2010年杨海晨博士翻译版。该量表为目前世界范围内最常用的双相障碍筛查量表&#xff0c;目前在精神科门诊最为常用的量表之一。 双向情感障碍筛查量表&#xff0c;也叫…

【linux】查看CPU的使用率

命令1&#xff1a;top top 总体系统信息 uptime&#xff1a;系统的运行时间和平均负载。tasks&#xff1a;当前运行的进程和线程数目。CPU&#xff1a;总体 CPU 使用率和各个核心的使用情况。内存&#xff08;Memory&#xff09;&#xff1a;总体内存使用情况、可用内存和缓存…

我记不住的getopt_long的那些参数和返回值

前言&#xff1a;最近在学习面向Linux系统进行C语言的编程&#xff0c;通过查询man手册和查看网络上的各种文章来获取一点点的知识&#xff0c;重点是看完手册还是一脸懵逼&#xff0c;搞不懂手册里面再说啥&#xff0c;而本篇文章将记录一下学习getopt_long的那些参数和返回值…