c++ - 模拟实现set、map

news2024/12/31 6:35:46

文章目录

  • 前言
    • 一、set模拟实现
    • 二、map模拟实现


前言

在C++标准库中,std::set 和 std::map都是非常常用的容器,它们提供了基于键值对的存储和快速查找能力。然而,关于它们的底层实现,C++标准并没有强制规定具体的数据结构,只是规定了它们的行为特性(如唯一性、有序性等)。不过,大多数C++标准库实现(如GCC的libstdc++和Clang的libc++)都采用了红黑树(Red-Black> Tree)作为std::set和std::map的底层数据结构。

下面都是基于红黑树实现的set和map。


一、set模拟实现

当前的红黑树需要这三个类型参数(键值、数据,通过数据求key的仿函数),这是为了map也能够复用,但是set只传入一个数据,所以采用这样的方式:<K, const K,Setfunc< K >>,因为set中的数据是不能被修改的所以在第二个类型中加上const

1、基本框架

//获取红黑树key的函数
template <class K>
struct Setfunc
{
	K operator()(const K& val)
	{
		return val;
	}
};

template <class K, class KeyOfValue = Setfunc<K>>
class set
{
public:
	//红黑树
	typedef RBTree<K, const  K, KeyOfValue> RB;

	private:
		//红黑树
		RB _rbset;
	};

2、迭代器
这里的迭代器直接复用红黑树的迭代器。


/*
第一 K类型是作为键值给删除,查找等需要键值的接口使用的
第二 const K是作为数据,给插入等接口使用
第三 KeyOfValue是仿函数,是给红黑树将数据类型转化为key使用,如插入时使用
*/
//迭代器
typedef typename RBTree<K,const K, KeyOfValue>::Iterator  iterator;
typedef typename RBTree<K, const K, KeyOfValue>::ConstIterator  cosnt_iterator;

//迭代器
iterator begin()
{
	return _rbset.Begin();
}

iterator end()
{
	return _rbset.End();
}

cosnt_iterator begin() const
{
	return _rbset.Begin();
}

cosnt_iterator end() const
{
	return _rbset.End();
}

3、插入、删除、查找、清空
以上接口均复用红黑树接口

//插入
pair<bool, iterator> insert(const K & val)
{
	return 	_rbset.Insert(val);
}

//删除
bool erase(const K& key)
{
	return _rbset.Erase(key);
}

//查找
iterator find(const K& key)
{
	return _rbset.Find(key);
}

//清空
bool clear()
{
	_rbset.Clear();
}

4、拷贝构造和赋值重载
(1)拷贝构造:
遍历需要拷贝的对象,再插入到新的对象里。

set(const set<K, KeyOfValue> & p) 
{
	//遍历set,重新插入
	set<K, KeyOfValue>::cosnt_iterator it = p.begin();
	while (it != p.end())
	{
		insert(*it);
		++it;
	}
};

(2)赋值重载:
比拷贝构造多一步,就是在插入前需要清空。

set<K, KeyOfValue>& operator=(const set<K, KeyOfValue>& p)
{
	//清空当前set
	clear();

	//遍历set,重新插入
	set<K, KeyOfValue>::cosnt_iterator it = p.begin();
	while (it != p.end())
	{
		insert(*it);
		++it;
	}
}

5、测试

void test_set()
{

	set<int> _s;
	
	//插入
	for (int i = 0; i < 10; i++)
	{
		_s.insert(i);
	}
	
	cout << "s1: ";
	set<int> s1 = _s;	//拷贝构造
	//迭代器遍历
	set<int>::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	cout << "s2: ";
	set<int> s2;
	s2 = s1;	//赋值
	//删除
	s2.erase(1);
	s2.erase(5);
	s2.erase(4);
	s2.erase(8);
	//迭代器遍历
	set<int>::iterator it2 = s2.begin();
	while (it2 != s2.end())
	{
		cout << *it2 << " ";
		++it2;
	}
	cout << endl;
}

在这里插入图片描述

6、总代码

//获取红黑树key的函数
template <class K>
struct Setfunc
{
	K operator()(const K& val)
	{
		return val;
	}
};

template <class K, class KeyOfValue = Setfunc<K>>
class set
{
public:
	//红黑树
	typedef RBTree<K, const  K, KeyOfValue> RB;
	/*
	第一 K类型是作为键值给删除,查找等需要键值的接口使用的
	第二 const K是作为数据,给插入等接口使用
	第三 KeyOfValue是仿函数,是给红黑树将数据类型转化为key使用,如插入时使用
	*/
	//迭代器
	typedef typename RBTree<K,const K, KeyOfValue>::Iterator  iterator;
	typedef typename RBTree<K, const K, KeyOfValue>::ConstIterator  cosnt_iterator;

	//构造
	set() {};
	set(const set<K, KeyOfValue> & p) 
	{
		//遍历set,重新插入
		set<K, KeyOfValue>::cosnt_iterator it = p.begin();
		while (it != p.end())
		{
			insert(*it);
			++it;
		}
	};

	set<K, KeyOfValue>& operator=(const set<K, KeyOfValue>& p)
	{
		//清空当前set
		clear();

		//遍历set,重新插入
		set<K, KeyOfValue>::cosnt_iterator it = p.begin();
		while (it != p.end())
		{
			insert(*it);
			++it;
		}

		return *this;
	}

	//析构
	~set() {};

	//迭代器
	iterator begin()
	{
		return _rbset.Begin();
	}

	iterator end()
	{
		return _rbset.End();
	}

	cosnt_iterator begin() const
	{
		return _rbset.Begin();
	}

	cosnt_iterator end() const
	{
		return _rbset.End();
	}

	//插入
	pair<bool, iterator> insert(const K & val)
	{
		return 	_rbset.Insert(val);
	}

	//删除
	bool erase(const K& key)
	{
		return _rbset.Erase(key);
	}

	//查找
	iterator find(const K& key)
	{
		return _rbset.Find(key);
	}
	
	//清空
	void  clear()
	{
		_rbset.Clear();
	}

private:
	//红黑树
	RB _rbset;
};

二、map模拟实现

map给红黑树传的类型为:<K, pair<const K, V, KeyOfValue> ,K类型用于删除、查找等,pair<const K, V,>作为数据插入,KeyOfValuepair<const K, V,>中的K类型,又因为键值不能修改所以pair<const K, V,>中的K加上const修饰。

1、基础框架

//获取 pair<K,V>中的key
template <class K,class V>
struct Mapfunc
{
	K operator()(const pair<K,V>& val)
	{
		return val.first;
	}
};

template <class K, class V, class KeyOfValue = Mapfunc<K,V>>
class map
{
public:
	//重命名
	typedef RBTree<K, pair<const K, V>, KeyOfValue> RB;
private:
	//红黑树
	RB _rbmap;
};

2、迭代器
依旧是复用红黑树迭代器即可。

typedef typename RB::Iterator  iterator;
typedef typename RB::ConstIterator  const_iterator;

iterator begin()
{
	return _rbmap.Begin();
}

iterator end()
{
	return _rbmap.End();
}

const_iterator begin() const 
{
	return _rbmap.Begin();
}

const_iterator end()const 
{
	return _rbmap.End();
}

3、插入、删除、查找、清空
依旧是复用红黑树接口即可。

//插入
pair<bool,iterator> insert(const pair<K, V>& val)
{
	return _rbmap.Insert(val);
}

//删除
bool erase(const K& key)
{
	return _rbmap.Erase(key);
}

//查找
iterator find(const K& key)
{
	return _rbmap.Find(key);
}

//清空
void  clear()
{
	_rbmap.Clear();
}

4、重载[ ]
当key不存在时,重载[ ]就会用key进行插入操作并返回插入后key对应数据的引用(此时key对应数据是用其默认构造进行初始化的),当key存在时,返回key对应数据的引用。

//重载[]
V& operator[](const K& key)
{
	pair<bool, iterator> ret = insert(make_pair(key, V()));
	return ret.second->second;
}

5、拷贝构造和赋值构造
(1)遍历需要拷贝的对象并将其数据插入当前对象即可。

map(const map<K,V, KeyOfValue> & p) 
{
	map<K, V, KeyOfValue>::const_iterator it = p.begin();
	while (it != p.end())
	{
		insert(*it);
		++it;
	}
};

(2)先清空再遍历插入当前对象即可。

map<K, V, KeyOfValue>& operator=(const map<K, V, KeyOfValue>& p)
{
	clear();

	map<K, V, KeyOfValue>::const_iterator it = p.begin();
	while (it != p.end())
	{
		insert(*it);
		++it;
	}

	return *this;
}

6、测试

 void test_map()
{
	//默认构造
	map<int, int> m;
	//插入
	for(int i = 1; i < 10; i++)
		m.insert({ i,i });
	
	//迭代器遍历
	cout << "m1:";
	//拷贝构造
	map<int, int> m1 = m;
	map<int, int>::iterator it1 = m1.begin();
	while (it1 != m1.end())
	{
		cout << it1->second << " ";
		++it1;
	}
	cout << endl;
	cout << "m2:";
	//赋值
	map<int, int> m2;
	m2 = m;

	//删除
	m2.erase(1);
	m2.erase(2);

	//使用[]
	m2[3] = 100;
	m2[4] = 100;

	map<int, int>::iterator it2 = m2.begin();
	while (it2 != m2.end())
	{
		cout << it2->second << " ";
		++it2;
	}

}

在这里插入图片描述
7、总代码

template <class K,class V>
struct Mapfunc
{
	K operator()(const pair<K,V>& val)
	{
		return val.first;
	}
};
template <class K, class V, class KeyOfValue = Mapfunc<K,V>>
class map
{
public:
	typedef RBTree<K, pair<const K, V>, KeyOfValue> RB;
	typedef typename RB::Iterator  iterator;
	typedef typename RB::ConstIterator  const_iterator;
	map() {};
	~map() {};

	map(const map<K,V, KeyOfValue> & p) 
	{
		map<K, V, KeyOfValue>::const_iterator it = p.begin();
		while (it != p.end())
		{
			insert(*it);
			++it;
		}
	};

	map<K, V, KeyOfValue>& operator=(const map<K, V, KeyOfValue>& p)
	{
		clear();

		map<K, V, KeyOfValue>::const_iterator it = p.begin();
		while (it != p.end())
		{
			insert(*it);
			++it;
		}

		return *this;
	}

	//迭代器
	iterator begin()
	{
		return _rbmap.Begin();
	}

	iterator end()
	{
		return _rbmap.End();
	}

	const_iterator begin() const 
	{
		return _rbmap.Begin();
	}

	const_iterator end()const 
	{
		return _rbmap.End();
	}

	//插入
	pair<bool,iterator> insert(const pair<K, V>& val)
	{
		return _rbmap.Insert(val);
	}

	//删除
	bool erase(const K& key)
	{
		return _rbmap.Erase(key);
	}

	//查找
	iterator find(const K& key)
	{
		return _rbmap.Find(key);
	}

	//重载[]
	V& operator[](const K& key)
	{
		pair<bool, iterator> ret = insert(make_pair(key, V()));
		return ret.second->second;
	}

	//清空
	void  clear()
	{
		_rbmap.Clear();
	}

private:
	RB _rbmap;
};

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

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

相关文章

【数据结构】——链式二叉树

目录 一、链式二叉树的定义结构 二、链式二叉树的遍历 2.1前序遍历 2.2中序遍历 2.3后序遍历 2.4层序遍历 三、链式二叉树的基本功能函数 3.1结点个数 3.2叶子结点个数 3.3二叉树第k层结点个数 3.4查找值为x的结点 3.5二叉树的销毁 四、基础OJ 4.1二叉树遍历 4.2…

2023-2024年 Java开发岗面试题经验分享

在各行各业中&#xff0c;面试前我们总会思索一个问题&#xff1a;究竟什么样的求职者能获得面试官的青睐&#xff1f;作为求职者&#xff0c;我们又该如何准备&#xff0c;以应对各种面试官的挑战&#xff1f;在这激烈的竞争里&#xff0c;如何才能让自己从众多应聘者中脱颖而…

镭速FTP替代升级页面助力企业创造新创安全运行环境

在当今快速发展的信息技术环境和日益严峻的网络安全挑战下&#xff0c;企业面临着数据传输和文件管理方面的重大挑战。特别是在信创环境下&#xff0c;传统的FTP已逐渐无法满足现代企业的需求&#xff0c;这促使企业寻求更高效、安全的替代方案。 企业在信创环境运行中的挑战 …

(ICLR-2024)PIXART-α:扩散Transformer的快速训练,用于逼真的文本到图像合成

PIXART-α&#xff1a;扩散Transformer的快速训练&#xff0c;用于逼真的文本到图像合成 Paper Title:PIXART-α: FAST TRAINING OF DIFFUSION TRANSFORMER FOR PHOTOREALISTIC TEXT-TO-IMAGE SYNTHESIS Paper是华为诺亚方舟实验室发表在ICLR 2024的工作 Paper地址 Code地址 项…

由浅入深的了解进程(4)

进程 1、优先级1、1、什么是优先级1、2、为什么需要优先级1、3、Linux优先级的特点和查看方式 2、补充概念3、命令行参数4、环境变量 1、优先级 1、1、什么是优先级 和生活中的概念其实是差不多的。优先级在进程中的定义是指定进程获得CPU资源的先后顺序。如果换一个视角的话…

ATF加载自定义镜像

实际上包含了两个问题&#xff1a; 如何把自定义的二进制文件打包到fip.bin中&#xff1f;如何在secure boot流程中load和认证自定义的二进制文件&#xff1f; 如何打包 证书创建工具和FIP打包工具是通过命令行传参的方式进行证书创建和打包的&#xff0c;如下&#xff1a; …

图新地球-新图源来一波(地表覆盖物、地表水、岩土圈)

0.序 以前的GlobalLand30图源不可访问了&#xff0c;很多需要地物分类的朋友很苦恼。 现在星图新上了一批图源&#xff0c;不仅包括地物分类、水域、还包括土壤酸碱度、有机碳、粘土、阳离子等各种岩土相关的地图服务。 这边全部配置成了图新地球可以直接加载的图源&#xff…

人生总会有自认为迈不过去的坎【西藏旅记1】

人生总会有自认为迈不过去的坎 孤独&#xff0c;也是人生一态。 有两个人说过我这样的性格&#xff0c;不会有真正的朋友&#xff0c;一个是旅行时的领队&#xff0c;另一个也是旅行时的领队。 以他们的视角&#xff0c;形形色色的人&#xff0c;应接不暇的景&#xff0c;他们修…

Github 2024-08-01 开源项目日报Top10

根据Github Trendings的统计,今日(2024-08-01统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量非开发语言项目3Go项目2Python项目2C项目1C#项目1Rust项目1TypeScript项目1编程面试大学:成为软件工程师的全面学习计划 创建周期:2859 天协议…

如何基于欧拉系统完成本地软件仓库安装

挂载 [rootlocalhost ~]# mount /dev/sr0/openeuler/ 查看一下 在脚本里添加以下两行 [rootlocalhost ~]# vim /etc/rc.d/rc.local 给一个可执行权限&#xff0c;并重启 [rootlocalhost ~]# chmod x /etc/rc.d/rc.local [rootlocalhost ~]# reboot 记住挂载点 切换到 /et…

CANoe系统变量模块里定义的结构体类型和变量从CAPL代码角度理解

CAPL里声明一个结构体类型&#xff1a; variables {struct DoIPMessage{byte version;byte inVersion;word type;dword length;byte payload[1500];};struct DoIPMessage doipMessage; }声明一个结构体类型DoIPMessage&#xff0c;定义了一个此结构体…

【C语言】C语言期末突击/考研--指针(一篇就够)

目录 一、指针的本质&#xff08;间接访问原理&#xff09; 1.1.指针的定义 1.2.取地址操作符与取值操作符&#xff0c;指针本质 二、指针的传递使用场景 2.1.什么是指针的传递 2.2.指针的传递使用场景 三、指针的偏移使用场景 3.1.指针的偏移 3.2.指针与一维数组 四…

风景视频素材高清无水印的网站有哪些?6个热门素材网站分享

高清无水印风景视频素材网站推荐&#xff0c;让您的视频内容独树一帜&#xff01; 对于视频创作者来说&#xff0c;一段引人入胜的风景视频素材往往能够瞬间抓住观众的注意力&#xff0c;仿佛将他们带入了一个全新的世界。然而&#xff0c;很多创作者在实际拍摄过程中会面临时…

(二)springboot2.7.6集成activit5.23.0之集成设计器

引入官方流程设计器 1. activiti-webapp-explorer2-5.23.0.war项目并解压。 2.将文件夹diagram-viewer和editor-app以及modeler.html拷贝到项目resources/static目录下&#xff1a; 顺便说一下&#xff1a; 在Spring Boot中&#xff0c;静态资源的访问顺序是先找static&#…

QT 安装指南

简介 Qt 是一个跨平台的应用程序开发框架&#xff0c;被广泛应用于桌面、移动设备和嵌入式系统等领域。本文将详细介绍如何在 Windows 操作系统上安装 Qt 5.14.2 版本(这个版本较为稳定适用)。 安装前准备 操作系统: 确保您的计算机运行的是 Windows 10 或更高版本。硬件要求…

【数据结构初阶】二叉树与堆(一)

文章目录 一、树的基础概念1、节点与度数2、树的度与高度3、引入&#xff1a;数组下标为何从0开始4、祖先节点5、树是递归定义的6、树与非树的区别7、代码表示 二、二叉树2.1、满二叉树2.2、完全二叉树2.3、完全二叉树的存储 三、堆 一、树的基础概念 1、节点与度数 节点分为…

app逆向实战之定位关键代码

前言 在保证App能够正常使用的前提下&#xff0c;我们可以通过抓包查看是否存在抓包检测。如果可以进行抓包&#xff0c;我们首先进行登录代码定位&#xff0c;并伪造请求进行登录&#xff0c;然后实现App中的某个功能。本文以某嘟牛app为例&#xff0c;抓包结果如下&#xff…

【投标】运维服务方案(2024Word完整版)

1.项目情况 2.服务简述 2.1服务内容 2.2服务方式 2.3服务要求 2.4服务流程 2.5工作流程 2.6业务关系 2.7培训 3.资源提供 3.1项目组成员 3.2服务保障 软件资料清单列表部分文档&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&a…

vue后台管理系统 vue3+vite+pinia+elementui+axios下

这篇文章来完成用户组件 也就是增删改查表格 用户页面信息页面由头部&#xff0c;表格,和弹框组成 <template><div class"user-header"><el-button type"primary" click"handleAdd">新增</el-button><el-form :inl…

(2024,LlamaGen,Llama,自回归下一token预测,模型扩展)自回归模型优于扩散:Llama 用于可扩展图像生成

Autoregressive Model Beats Diffusion: Llama for Scalable Image Generation 目录 0. 摘要 1. 引言 2. 自回归模型在图像生成中的应用 2.1 概述 2.2 图像 tokenizer 2.3 自回归模型生成图像 2.4 规模扩展 2.5 服务 3. 实验 5. 结论 0. 摘要 我们介绍 LlamaGen&…