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.hqwc.cn/news/186070.html

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

相关文章

千兆光模块和万兆光模块需要注意哪些事项

随着网络通信技术的发展&#xff0c;千兆光模块和万兆光模块已经成为了网络设备中不可或缺的关键组件。光模块的制造涉及到许多技术和工艺问题&#xff0c;需要严格的控制和管理。本文将从工艺流程、材料选用、测试认证等方面&#xff0c;详细介绍制造千兆光模块和万兆光模块需…

储能领域 / 通讯协议 / 技术栈 等专有名字集锦——主要收集一些储能领域的专有名词,以及相关的名词

目录 名词解释ModbusIOT设备通讯协议 CAN/ RS-485 储能术语电池管理系统BMS电池储能系统相关概念&#xff0c;总控&#xff0c;主控&#xff0c;从控 电池相关知识拆解电池的构成逆变器 电池核心参数SOC 电池剩余容量 名词解释 英文中文biz layer业务层与业务层通信的服务CRC循…

【MySQL8】1130 - Host *** is not allowed to connect to this MySOL server

问题描述 使用 Navicat 连接 MySQL8 报错&#xff1a; 1130 - Host *** is not allowed to connect to this MySOL server解决方案 use mysql;select host ,user from user; -- 将 root 用户的主机&#xff08;host&#xff09;值修改为 %&#xff0c;即允许从任何主机连接 …

Kubernetes学习-概念2

参考&#xff1a;关于 cgroup v2 | Kubernetes 关于 cgroup v2 在 Linux 上&#xff0c;控制组约束分配给进程的资源。 kubelet 和底层容器运行时都需要对接 cgroup 来强制执行为 Pod 和容器管理资源&#xff0c; 这包括为容器化工作负载配置 CPU/内存请求和限制。 Linux 中…

叙永微公益:开展“活水计划-益童成长守护”周末陪伴活动

&#xff08;韩熙 林梅图/文&#xff09;2023年11月12日&#xff0c;叙永县微公益协会的志愿者们早早地驱车前往县内的孤困儿童家庭&#xff0c;与他们共同度过一个充实而温馨的周末。志愿者们不仅为孩子们带来了生活物资、零食、玩具等礼物&#xff0c;更重要的是&#xff0c;…

虾皮店铺所有商品数据接口(shopee.item_search_shop)

虾皮店铺所有商品数据接口可以提供丰富的电商数据&#xff0c;包括商品数据、订单数据、会员数据、评价数据等。以下是具体的介绍&#xff1a; 商品数据&#xff1a;虾皮提供了商品的基本信息&#xff0c;包括商品名称、描述、规格、价格、销量、库存等信息。此外&#xff0c;…

开源电子画册源码系统 可重复利用 适合任何行业 带完整的搭建教程

电子画册&#xff0c;又称电子样本、电子商刊、电子杂志&#xff0c;是一种集合图片处理、文案策划、音乐加工、视频、统计调查、虚拟现实、三维动画等多种技术和表现形式为一体的多媒体画册&#xff0c;电子杂志是纸质印刷画册&#xff08;样本&#xff09;的升级版本&#xf…

idea一键打包docker镜像并推送远程harbor仓库的方法(包含spotify和fabric8两种方法)--全网唯一正确,秒杀99%水文

我看了很多关于idea一键打包docker镜像并推送harbor仓库的文章&#xff0c;不论国内国外的&#xff0c;基本上99%都是瞎写的&#xff0c; 这些人不清楚打包插件原理&#xff0c;然后就是复制粘贴一大篇&#xff0c;写了一堆垃圾&#xff0c;然后别人拿来也不能用。 然后这篇文…

GAT里面的sofamax函数的实现:

1.sofamx 公式&#xff1a; 2. GAT里的sofamax函数的实现&#xff1a; 1. 因为指数在x轴正轴爆炸式地快速增长&#xff0c;如果zi比较大&#xff0c;exp⁡(zi)也会非常大&#xff0c;得到的数值可能会溢出。溢出又分为下溢出&#xff08;Underflow&#xff09;和上溢出&#x…

为什么嵌入式没有35岁危机?

为什么嵌入式没有35岁危机? 在当今数字化时代&#xff0c;IT行业变化迅速&#xff0c;技术的更新迭代速度惊人。然而&#xff0c;有一个技术领域却能够在这个竞争激烈的行业中稳步前行&#xff0c;而且不受35岁危机所困扰&#xff0c;那就是嵌入式技术。 嵌入式技术是指将计算…

Nginx的使用

Nginx的使用 1、反向代理一 实现效果&#xff1a;使用 nginx 反向代理&#xff0c;访问 www.123.com 直接跳转到 127.0.0.1:8080 准备工作 : &#xff08;1&#xff09;在 linux 系统安装 tomcat&#xff0c;使用默认端口 8080 &#xff08;2&#xff09;tomcat 安装文件放…

使用html2canvas转换table为图片时合并单元格rowspan失效,无边框显示问题解决(React实现)

最近使用 html2canvas导出Table表单为图片&#xff0c;但是转换出的图片被合并的单元格没有显示边框 查了原因是因为我为tr设置了背景色&#xff0c;然后td设置了rowspan&#xff0c;设置了rowspan的单元格就会出现边框不显示的问题。 解决方法就是取消tr的背景色&#xff0c;然…