C++之map和set 的封装

通过红黑树的学习(C++之红黑树-CSDN博客)让我了解到map和set的底层如何实现,这一次我们来对map和set进行封装。

目录

1.map和set底层原理

 2.map和set的定义

 3.map和set的仿函数

4.map和set的插入

5.map和set的迭代器

5.1迭代器的构造

5.2解引用

5.3成员访问操作符

5.4 == 与!=

5.5begin()

5.6end()

5.7++

 5.8--

 6.map总体代码

7.set总体代码


1.map和set底层原理

 我们都知道map和set的底层都是红黑树,但是map是kv模型,set是k模型,对于红黑树来说这两种不同的模型 可以通过控制模版参数来区分。

map简化后的源码

template<class Key,class T,class Compare = less<Key>,class Alloc=alloc>
class map
{
public:
	typedef Key ket_type;
	typedef T data_type;
	typedef pair<const Key, T> value_type;
private:
	typedef rb_tree < key_type, value_type,
		selectlst<value_type>, key_compare, Alloc> rep_type;
};

set简化后的源码:

template<class Key, class Compare = less<Key>, class Alloc = alloc>
class set
{
public:
	typedef Key ket_type;
	typedef Key data_type;
	typedef Compare key_type;
	typedef Compare value_compare;
private:
	typedef rb_tree < key_type, value_type,
		identity<value_type>, key_compare, Alloc> rep_type;
};

 那么红黑树是怎么通过模板来区分map和set 的呢?


rb_tree 的 value 决定 是map的key/value 还是 set的key:

如果是set容器,那么它传入底层红黑树的模板参数就是Key和Key:

    template<class K>
    class set
    {
      private:
        RBTree<K,K> _t;
    };

如果是map容器,传入底层红黑树的模板参数就是Key和Key和value的键值对:

    class map
    {
    private:
        RBTree<K, pair<const K,V>> _t;
    };

通过上面,我们可以知道,对于set和map的区别:我们只要通过第二个模板参数就能进行区分那是不是第一个模板参数就没有意义了呢?

    对于insert(const Value&v)来说,需要放入存入的值,确实是这个样子的,插入的值是value,对于set就是key,对于map就是pair。
    但是对于find(const Key&key)来说,查找的参数不是value,找的不是pair而是Key,对于map容器来说就不行了。

 2.map和set的定义

set:

template<class K>
class set
{
private:
RBTree<K,K> _t;
};

map:

class map
{
private:
RBTree<K, pair<const K,V>> _t;
}

 3.map和set的仿函数

我们将传入的data直接进行比较

Q:

对于set是Key,可以比较
 对于map是pair,我们无法直接进行比较,我们的期望是使用pair键值对中的first去比较,与second无关。

由于底层的红黑树不知道传的是map还是set容器,当需要进行两个结点键值的比较时,底层红黑树传入的仿函数来获取键值Key,进行两个结点键值的比较:这个时候我们就需要仿函数了,如果是set那就是用于返回T当中的键值Key,如果是map那就是用于返回pair的first:

仿函数/函数对象也是类,是一个类对象。仿函数要重载operator() 

map:

namespace bt
{
	template<class K, class V>
	class map
	{
		struct MapkeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
}

set:

namespace bt
{
	template <class K>
	class set  // 仿函数,重载operator()
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
 
		};
}

 

 我们的查找函数如下:

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;
	}
}

4.map和set的插入

直接cv大法,从红黑树那里拿到了代码

//map
bool insert(const pair<K, V>& kv)
{
	return _t.Insert(kv);
}
 
//set
bool insert(const K& key)
{
	return _t.Insert(key);
}

5.map和set的迭代器

5.1迭代器的构造

template<class T,class Ref,class Ptr>
struct __RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T,Ref,Ptr> Self;
	typedef __RBTreeIterator<T, T&, T*> iterator;
	Node* _node;
 
	__RBTreeIterator(Node*node)
		:_node(node)
	{}
 
	//普通迭代器的时候,它是拷贝构造
	//const迭代器的时候,它是构造,支持用普通迭代器构造const迭代器
	__RBTreeIterator(const iterator& s)
		:_node(s._node)
	{}
}

5.2解引用

Ref operator*()
	{
		return _node->_data;
	}

5.3成员访问操作符

Ptr operator->()
	{
		return &_node->_data;
	}

5.4 == 与!=

  bool operator !=(const Self & s) const
	{
		return _node != s._node;
	}
	bool operator ==(const Self& s) const
	{
		return _node == s._node;
	}

5.5begin()

begin():返回中序(左、根、右)第一个结点的正向迭代器,即最左节点,返回的是最左节点,直接找最左节点即可

template<class K, class T,class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __RBTreeIterator<T> iterator;
 
	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		return iterator(left);
	}
}

5.6end()

end():返回中序(左、根、右)最后一个结点下一个位置的正向迭代器,这里用空指针

template<class K, class T,class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __RBTreeIterator<T> iterator;
 
	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		return iterator(left);
	}
 
	iterator end()
	{
		return iterator(nullptr);
	}
}

5.7++

	Self& operator++()
	{
		if (_node->_right)
		{
			Node* min = _node->_right;
			while (min->_left)
			{
				min = min->_left;
			}
			_node = min;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

一个结点的正向迭代器进行++操作后,根据红黑树中序(左、根、右)找到当前结点的下一个结点,中序的第一个节点是最左,迭代器的++怎么去找:

  • 如果节点的右子树不为空++就是找右子树的最左节点
  • 如果节点的右子树为空++就是找祖先(孩子是父亲的左的那个祖先

 5.8--

Self& operator--()
	{
		if (_node->_left)
		{
			Node* max = _node->_left;
			while (max->_right)
			{
				max = max->_right;
			}
			_node = max;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&&cur==parent->_left)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

如果是根,–就是左子树,找到左子树最大的那一个(最右节点)

  • 如果节点的左子树不为空,--找左子树最右的节点
  • 如果节点的左子树为空,--找祖先(孩子是父亲的右的祖先)

 6.map总体代码

#include"RBTree.h"
 
namespace bt
{
	template<class K, class V>
	class map
	{
		struct MapkeyOfT 
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		//typename:没有实例化的模板,区分不了是静态变量还是类型,typename告诉编译器是类型
		typedef typename RBTree<K, pair<const K, V>, MapkeyOfT>::iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, MapkeyOfT>::const_iterator
			const_iterator;
 
		iterator begin()
		{
			return _t.begin();
		}
		iterator end()
		{
			return _t.end();
		}
 
		const_iterator begin() const
		{
			return _t.begin();
		}
		const_iterator end() const
		{
			return _t.end();
		}
		pair<iterator, bool> insert(const pair<const K, V>& kv)
		{
			return _t.Insert(kv);
		}
 
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		RBTree<K, pair<const K, V>, MapkeyOfT> _t;
	};
 
}

7.set总体代码

#include"RBTree.h"
 
namespace bt
{
	template <class K>
	class set  // 仿函数,重载operator()
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
 
		};
	
	public:
		//typename:没有实例化的模板,区分不了是静态变量还是类型,typename告诉编译器是类型
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;//key不可以修改
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
 
		iterator begin() const
		{
			return _t.begin();
		}
 
		iterator end() const
		{
			return _t.end();
		}
 
		pair<iterator, bool> insert(const K& key)
		{
	
			pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
			return pair<iterator, bool>(ret.first, ret.second);//用普通迭代器构造const迭代器
		}
 
	private:
		RBTree<K, K, SetKeyOfT> _t;
	
	};
 
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决Android手机无法通过蓝牙给win10 PC传送文件

&#xff08;一&#xff09;先配对设备&#xff0c;正常配对就可以 &#xff08;二&#xff09;打开系统设置&#xff0c;win搜索窗口搜索“设置” &#xff08;三&#xff09;搜索“蓝牙” &#xff08;四&#xff09;打开“蓝牙和其他设备”&#xff0c;点击“更多蓝牙设置”…

四款不同类型的企业防泄密软件推荐

在数字化快速发展的今天&#xff0c;企业数据的安全与保密显得愈发重要。防泄密软件作为一种专门的数据保护工具&#xff0c;已经逐渐成为企业不可或缺的安全屏障。本文将深入探讨防泄密软件对企业的意义&#xff0c;并介绍一些市面上主流的防泄密软件。 首先&#xff0c;防泄密…

【MySQL复合查询】

文章目录 一、基本的使用案例二、多表查询三、自连接四、子查询4.1单行子查询4.2多行子查询in关键字all关键字any关键字 4.3多列子查询4.4 在from子句中使用子查询 解决多表问题的本质五、合并查询1.union2.union all 一、基本的使用案例 注明&#xff1a;以下案例使用的均为一…

Spring-依赖查找

依赖查找 根据名称进行查找 实时查找 BeanFactory beanFactory new ClassPathXmlApplicationContext("beans.xml"); Object bean beanFactory.getBean("personHolder"); System.out.println(bean);xml如下: <bean id"person" class&qu…

【数据可视化01】matplotlib实例介绍2

目录 一、引言二、实例介绍1.箱线图2.热力图3.线条形式 一、引言 接着上一文章【数据可视化01】matplotlib实例介绍1继续介绍matplotlib的实例。 二、实例介绍 在matplotlib中&#xff0c;常用的图形类型包括&#xff1a; 箱线图&#xff08;Box plot&#xff09;&#xff1…

非预警,这3本TOP期刊,为何走到On Hold这步?

本周投稿推荐 SSCI • 2区社科类&#xff0c;3.0-4.0&#xff08;社科均可&#xff09; EI • 计算机工程类&#xff08;接收广&#xff0c;录用极快&#xff09; SCI&EI • 4区生物医学类&#xff0c;1.5-2.0&#xff08;录用率99%&#xff09; • 1区工程类&#…

如何用时尚新姿讲好中国品牌故事?

品牌建设在推动高质量发展中扮演了双重角色&#xff0c;既是高质量发展的重要“承载者”&#xff0c;也是强有力的“助推器”。5月10日-11日&#xff0c;中国时尚品牌URBAN REVIVO&#xff08;以下简称UR&#xff09;以中国品牌日为起点&#xff0c;联合天猫超级品牌日&#xf…

Spring框架深度解析:打造你的Java应用梦工厂

想要在Java企业级应用开发中大展身手&#xff1f;Spring框架的核心容器是你不可或缺的伙伴&#xff01; 文章目录 一. 引言1.1 介绍Spring框架的重要性1.2 阐述核心容器在Spring框架中的作用1.3 故事开端 二. 背景介绍2.1 描述Spring框架的发展历程2.2 概述Spring框架的主要特点…

数学老师们

小学三年级之前的数学老师&#xff0c;包括学前班给过我零分的数学老师&#xff0c;模样、姓名都不记得了。能回忆起来的最早的数学老师是四、五年级的李成娥老师。 李老师四十岁左右&#xff0c;短发&#xff0c;温和、爱笑&#xff0c;尤其是在班主任张老师的衬托下&#xf…

有必要买超声波洗眼镜机吗?力荐四款实力超群超声波清洗机

在日常生活中&#xff0c;眼镜不仅仅是我们视野的延展&#xff0c;像太阳眼镜&#xff0c;也是有着独特的作用。但是&#xff0c;在每天的使用过程中&#xff0c;眼镜片表面难免会有灰尘&#xff0c;污迹&#xff0c;甚至油渍&#xff0c;这些都会对镜片的材质产生一定的损伤&a…

宝塔面板各种疑难杂症处理命令教程

下载地址&#xff1a;宝塔面板各种疑难杂症处理命令教程 这份宝塔面板各种疑难杂症处理命令教程&#xff0c;可以解决市面上遇到的各种难题&#xff0c;建议有技术能行的下载使用&#xff0c;小白也可以下载来学习可以帮助你解决宝塔面板遇到的各种难题

网络端口占用问题的综合调研与解决方案

原创 Randy 拍码场 问题背景 去年底信息安全团队进行网络权限治理&#xff0c;要求所有应用实例使用静态IP&#xff0c;公网访问策略与静态IP绑定&#xff1b;之后实例重启时偶现“端口被占用”错误。通过分析总结应用日志&#xff0c;共有以下4种错误类型&#xff0c;实质都是…

Apple store 静安·苹果店欣赏

官网&#xff1a; https://www.apple.com/today/Apple 亚洲第一大商店&#xff1a;Apple 静安零售店现已在上海开幕 静安苹果欣赏

LVGL移植到ARM开发板(GEC6818)

源码下载&#xff1a;点击跳转 下载好三个文件后&#xff0c;将其解压缩&#xff0c;并合到一个文件夹里面—— 1、修改 Makefile 删除 -Wshift-negative-value 2、修改 main.c 3、修改 lv_drv_conf.h 在lv_drv_conf.h文件屏幕驱动文件刚好与开发板LCD驱动文件一致&#xff0c…

【操作指南】银河麒麟高级服务器操作系统内核升级——基于4.19.90-17升级

1. 升级清单 升级包及依赖包清单如下。 kernel ARM架构 kernel-core-4.19.90-23.18.v2101.ky10.aarch64.rpm kernel-modules-4.19.90-23.18.v2101.ky10.aarch64.rpm kernel-4.19.90-23.18.v2101.ky10.aarch64.rpm kernel-modules-extra-4.19.90-23.18.v2101.ky10.aarch64.r…

【小笔记】neo4j用load csv指令导入数据

【小笔记】neo4j用load csv指令导入数据 背景 很久没有用load CSV的方式导入过数据了因为它每次导入有数量限制&#xff08;印象中是1K还是1W&#xff09;&#xff0c;在企业中构建的图谱往往都是大规模的&#xff0c;此时通常采用的是Neo4j-admin import方式。最近遇到了一些…

《二》菜单模块设计实现---添加动作函数等

在菜单栏中&#xff0c;比如&#xff1a; 我们要添加很多像新建&#xff0c;打开&#xff0c;粘贴&#xff0c;复制&#xff0c;加粗&#xff0c;下划线的动作&#xff0c;所以首先我们需要添加一些头文件&#xff1a; #include <QMainWindow> #include"mychild.h&…

麒麟信安连续四年被授予湖南省、长沙市“守合同重信用企业”双重荣誉称号

以诚为本&#xff0c;以信立身&#xff0c;**麒麟信安经过多年的市场积累&#xff0c;凭借健全的市场主体信誉机制&#xff0c;良好的社会信誉和合同履约能力&#xff0c;连续四年获评长沙市“守合同重信用”公示企业&#xff08;2023年度&#xff09;、湖南省“守合同重信用”…

OpenAI 或将推出多模态人工智能数字助理;研究发现部分 AI 系统已学会「说谎」丨 RTE 开发者日报 Vol.203

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

海洋环境保护论文阅读记录

海洋环境保护 论文1&#xff1a;Critical role of wave–seabed interactions in the extensive erosion of Yellow River estuarine sediments 波浪-海床相互作用在黄河河口广泛侵中的关键作用 estuatine 河口的&#xff0c;港湾的 erodibility侵蚀度 sediment erodibility …