[C++STL]C++ 实现map容器和set容器

代码如下:

#pragma once
#include <iostream>
using namespace std;enum COLOR
{BLACK, RED
};template<class V>//迭代器声明,定义在后面
struct RBTreeIterator;template<typename V>
struct RBTreeNode
{RBTreeNode<V> * _parent;RBTreeNode<V>* _left;RBTreeNode<V> *_right;V _val;COLOR _color;RBTreeNode(const V &val = V()) :_parent(nullptr), _left(nullptr), _right(nullptr), _val(val), _color(RED) {}};template<typename K, typename V, typename KeyOfValue>
class RBTree
{
public:typedef RBTreeNode<V> Node;typedef RBTreeIterator<V> iterator;RBTree() :_header(new Node){_header->_left = _header->_right = _header;}pair<iterator, bool> insert(const V &val){if (_header->_parent == nullptr){Node * root = new Node(val);_header->_parent = root;root->_parent = _header;_header->_left = _header->_right = root;//根结点为黑色root->_color = BLACK;return make_pair(iterator(root), true);}Node *cur = _header->_parent;Node *parent = nullptr;KeyOfValue kov;//1.寻找要插入的结点的位置while (cur){parent = cur;if (kov(cur->_val) == kov(val)) return make_pair(iterator(cur), false);else if (kov(cur->_val) > kov(val)) cur = cur->_left;else cur = cur->_right;}//2.创建结点cur = new Node(val);Node *node = cur;//记录插入的结点的位置,方便后面返回。if (kov(parent->_val) > kov(cur->_val)) parent->_left = cur;else parent->_right = cur;cur->_parent = parent;//3.颜色的修改或者结构的调整while (cur != _header->_parent && cur->_parent->_color == RED){parent = cur->_parent;Node *gfather = parent->_parent;if (gfather->_left == parent){Node *uncle = gfather->_right;//情况1.uncle存在且为红if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;gfather->_color = RED;//向上追溯cur = gfather;}else{if (parent->_right == cur)//情况3{RotateL(parent);swap(cur, parent);}//2.uncle不存在或者uncle为黑RotateR(gfather);parent->_color = BLACK;gfather->_color = RED;break;}}else{Node *uncle = gfather->_left;if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;gfather->_color = RED;cur = gfather;}else{if (parent->_left == cur){RotateR(parent);swap(cur, parent);}RotateL(gfather);parent->_color = BLACK;gfather->_color = RED;break;}}}//根结点为黑色_header->_parent->_color = BLACK;//更新头结点的左右指向_header->_left = leftMost();_header->_right = rightMost();return make_pair(iterator(node), true);}void RotateL(Node *parent){Node *subR = parent->_right;Node *subRL = subR->_left;parent->_right = subRL;if (subRL) subRL->_parent = parent;if (parent == _header->_parent){_header->_parent = subR;subR->_parent = _header;}else{Node *gfather = parent->_parent;if (gfather->_left == parent) gfather->_left = subR;else gfather->_right = subR;subR->_parent = gfather;}subR->_left = parent;parent->_parent = subR;}void RotateR(Node * parent){Node *subL = parent->_left;Node *subLR = subL->_right;parent->_left = subLR;if (subLR) subLR->_parent = parent;if (parent == _header->_parent){_header->_parent = subL;subL->_parent = _header;}else{Node *gfather = parent->_parent;if (gfather->_left == parent) gfather->_left = subL;else gfather->_right = subL;subL->_parent = gfather;}subL->_right = parent;parent->_parent = subL;}Node *leftMost(){Node *cur = _header->_parent;while (cur && cur->_left){cur = cur->_left;}return cur;}Node *rightMost(){Node *cur = _header->_parent;while (cur && cur->_right){cur = cur->_right;}return cur;}iterator begin(){return iterator(_header->_left);}iterator end(){return iterator(_header);}//反向迭代器iterator rbegin(){return iterator(_header->_right);}private:Node *_header;
};template<class V>
struct RBTreeIterator
{typedef RBTreeNode<V> Node;typedef RBTreeIterator<V> Self;Node *_node;RBTreeIterator(Node *node) :_node(node) {}V & operator*(){return _node->_val;}V * operator->(){return &_node->_val;}bool operator!=(const Self & it){return _node != it._node;}Self & operator++(){if (_node->_right)//存在右结点{//右子树的最左结点_node = _node->_right;while (_node->_left){_node = _node->_left;}}else//不存在右结点{Node *parent = _node->_parent;while (_node == parent->_right)//回溯{_node = parent;parent = parent->_parent;}//特殊情况:根结点没有右孩子,则不需要更新结点if (_node->_right != parent) _node = parent;}return *this;}Self & operator--(){if (_node->_left){//右子树的最左结点_node = _node->_left;while (_node->_right){_node = _node->_right;}}else{Node *parent = _node->_parent;while (_node == parent->_left){_node = parent;parent = parent->_parent;}if (_node->_left != parent) _node = parent;}return *this;}
};template<typename K, typename T>
class Map
{struct MapKeyOfValue{const K& operator()(const pair<K, T> & val){return val.first;}};public:typedef typename RBTree<K, pair<K, T>, MapKeyOfValue>::iterator iterator;pair<iterator, bool> insert(const pair<K, T> & kv){return _rbt.insert(kv);}T & operator[](const K &key){pair<iterator, bool> ret = _rbt.insert(make_pair(key, T()));return ret.first->second;}iterator begin(){return _rbt.begin();}iterator end(){return _rbt.end();}iterator rbegin(){return _rbt.rbegin();}private:typedef RBTree<K, pair<K, T>, MapKeyOfValue> rbt;rbt _rbt;
};template<typename K>
class Set
{struct SetKeyOfValue{const K & operator()(const K & val){return val;}};public:bool insert(const K &val){return _rbt.insert(val);}private:typedef RBTree<K, K, SetKeyOfValue> rbt;rbt _rbt;};

测试代码如下:

#include<iostream>
#include "Map.h"
using namespace std;int main()
{Map<int, int> m;m.insert(make_pair(1, 1));m.insert(make_pair(2, 1));m.insert(make_pair(3, 1));m.insert(make_pair(4, 1));Map<int, int>::iterator it = m.begin();while (it != m.end()){//it-> 获取结点的val的地址 => pair指针//pair->first获得pair对象的第一个值//pair->second获得pair对象的第二个值cout << it->first << " " << it->second << endl;++it;}Map<int, int>::iterator it1 = m.rbegin();while (it1 != m.end()){cout << it1->first << " " << it1->second << endl;--it1;}Map<int, int> m1;m1[1] = 1;m1[3] = 20;m1[2] = 300;m1[4] = 4000;Map<int, int>::iterator it2 = m1.begin();while (it2 != m1.end()){cout << it2->first << " " << it2->second << endl;++it2;}return 0;}

测试结果:
在这里插入图片描述

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

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

相关文章

多角度让你彻底明白yield语法糖的用法和原理及在C#函数式编程中的作用

如果大家读过dapper源码&#xff0c;你会发现这内部有很多方法都用到了yield关键词&#xff0c;那yield到底是用来干嘛的&#xff0c;能不能拿掉&#xff0c;拿掉与不拿掉有多大的差别&#xff0c;首先上一段dapper中精简后的Query方法&#xff0c;先让大家眼见为实。private s…

C++泛型编程实现哈希表(闭散列---线性探测)

代码如下: #include <iostream> #include <vector> using namespace std;enum STATE {EXIST,DELETE,EMPTY };template<typename K,typename V> struct HashNode {pair<K, V> _kv;STATE _state EMPTY; };template<typename K,typename V> class…

哪种开源许可证最适合商业化?

选择最佳开源许可证是为新项目所做的最重要的决定之一。大多数开发者会选用 MIT、BSD 或 Apache 等流行的宽松许可证&#xff08;permissive license&#xff09;。对于商业项目而言&#xff0c;这种选择不错&#xff0c;因为这能减少用户对项目的抵触情绪。当应用于开源项目时…

C++泛型编程实现哈希表(开散列法)

代码如下: #include <iostream> #include <vector> using namespace std;template<typename K> struct HashNode {typedef HashNode<K> Node;K _val;Node * _next;HashNode(const K & val):_val(val),_next(nullptr){} };template<typename K&…

数据结构与算法--分治算法-最大子序列和问题

分治算法 用于设计算法的一种常用技巧–分治算法&#xff08;divide and conquer&#xff09;。分治算法由两部分组成&#xff1a; 分(divide)&#xff1a;递归然后借机较小的问题&#xff08;基础情况除外&#xff09;治(conquer)&#xff1a;然后从子问题的解构建原问题的解…

请把我不会,换成我可以学

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份有位读者跟我说起自己的烦恼&#xff1a;“我到公司已经接近四年了&#xff0c;领导经常让我做一些岗位职责以外的事情。这些东西我都不会&#xff0c;还非让我做。并且一直没有职位上的改变&#xff0c;我怎…

[C++STL]C++实现unordermap容器和unorderset容器

代码如下: #include <iostream> #include <vector> using namespace std;template<typename K,typename V,typename KeyOfValue> class HashTable;//声明template<typename V> struct HashNode {typedef HashNode<V> Node;V _val;Node * _next;…

还不会docker+k8s?2020年,就要面对现实了...

docker的前世今生2010年&#xff0c;几个年轻人&#xff0c;在美国旧金山成立了一家名叫“dotCloud”的公司。这家公司主要提供基于PaaS的云计算技术服务。具体来说&#xff0c;是和LXC有关的容器技术。后来&#xff0c;dotCloud公司将自己的容器技术进行了简化和标准化&#x…

数据结构与算法--重建二叉树

二叉树 树在实际编程中经常遇到地一种数据结构。上一篇中我们解释了二叉树及其原理&#xff0c;从中可以知道&#xff0c;树地操作会涉及到很多指针地操作&#xff0c;我们一般遇到地树相关地问题差不多都是二叉树。二叉树最重要地莫过于遍历&#xff0c;即按照某一顺序访问树…

3分钟掌握Quartz.net分布式定时任务的姿势

长话短说&#xff0c;今天聊一聊分布式定时任务&#xff0c;我的流水账笔记&#xff1a;ASP.NET CoreQuartz.Net实现web定时任务AspNetCore结合Redis实践消息队列细心朋友稍一分析&#xff0c;就知道还有问题&#xff1a;水平扩展后的WebApp的Quartz.net定时任务会多次触发&…

数据结构与算法--利用栈实现队列

利用栈实现队列 上一节中说明了栈的特点 后进先出&#xff0c;我们用数组的方式实现了栈的基本操作api&#xff0c;因此我们对栈的操作是不考虑排序的&#xff0c;每个api的操作基本都是O(1)的世界&#xff0c;因为不考虑顺序&#xff0c;所以找最大&#xff0c;最小值&#x…

ASP.NET Core 配置源:实时生效

在之前的文章 ASP.NET Core 自定义配置源 和 ASP.NET Core etcd 配置源 中主要是介绍如何实现自定义的配置源&#xff0c;但不论内置的和自定义的配置源&#xff0c;都会面临如何使配置修改后实时生效的问题&#xff08;修改配置后在不重启服务的情况下能马上生效&#xff09;。…

分布式事务理论模型

分布式事务 事务的概念&#xff0c;我们第一想到的应该是数据库的事务。所谓数据库事务就是只作为单个逻辑工作单元执行多个数据库操作的时候&#xff0c;数据库需要保证要么都成功&#xff0c;要么都失败&#xff0c;它必须满足ACID特性&#xff0c;即&#xff1a; 原子性&…

[MySQL基础]数据库的相关概念

DB: 数据库(database):存储数据的“仓库”&#xff0c;它保存了一系列有组织的数据。 DBMS: 数据库管理系统(Database Management System):数据库是通过DBMS创建和操作的容器。 SQL: 结构化查询语言(Structure Query Language):专门用来与数据库通信的语言。 SQL的优点: 1.几…

Linq下有一个非常实用的SelectMany方法,很多人却不会用

在平时开发中经常会看到有些朋友或者同事在写代码时会充斥着各种for&#xff0c;foreach&#xff0c;这种程式代码太多的话阅读性特别差&#xff0c;而且还显得特别累赘&#xff0c;其实在FCL中有很多帮助我们提高阅读感的方法&#xff0c;而现实中很多人不会用或者说不知道&am…

.NET Core前后端分离快速开发框架(Core.3.1+AntdVue)

引言时间真快&#xff0c;转眼今年又要过去了。回想今年&#xff0c;依次开源发布了Colder.Fx.Net.AdminLTE(254Star)、Colder.Fx.Core.AdminLTE(335Star)、DotNettySocket(82Star)、IdHelper(47Star)&#xff0c;这些框架及组件都是本着以实际出发&#xff0c;实事求是的态度&…

数据结构与算法--查找与排序另类用法-旋转数组中的最小数字

查找与排序 查找 查找与排序都在程序设计中常被用到的算法。查找相对而言简单&#xff0c;一般都是顺序查找&#xff0c;二分查找&#xff0c;哈希表查找&#xff0c;和二叉排序树查找。其中二分查找是我必须熟悉的一种。哈希表和二叉排序树主要点在于他的数据结构而不是算法…

[MySQL基础]MySQL常见命令介绍

show databases; use 库名; show tables; show tables from 库名 select database(); create table 名字( id int, name varchar(20)); desc 表名; select * from 表名; insert into 表名 (a,b,…,f) values(1,2,3,…,7); update 库名 set name‘lilei’ where id1; delete f…

如何选择好公司

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份前几天写了一篇文章&#xff1a;怎么判断自己在不在一家好公司。附带了一个投票调查&#xff0c;结果如下图&#xff1a;调研结果有点点扎心&#xff0c;有点点出乎我的意料。61%的小伙伴&#xff0c;都认为自…