当前位置: 首页 > article >正文

【C++STL详解(十三)】unordered系列容器的介绍与使用

目录

前言

一、unordered_map

介绍

使用 

构造方式

修改 

容量

迭代器

元素访问

查询

桶操作 

二、unordered_set

介绍

使用

构造

修改

容量

 迭代器(只有单向)

查询

桶操作 

三、unordered系列的性能测试


前言

前面提到的map/set是C++98提供的关联式容器,底层结构是红黑树,最差情况下需要比较树得高度次,若树的结点十分多时,查询效率也不是很理想。C++11中,又提供了4个unordered系列容器,使用起来和map/set基本类似,只是底层结构不同。unordered系列底层是哈希结构(严格来说是哈希桶结构),最快的查询可以达到O(1)。

一、unordered_map

介绍

  • unordered_map是存储<key,value>键值对的关联式容器,KV模型
  • 键值key通常用于惟一地标识元素(不存在相同元素),而映射值是一个对象,其内容与此
    键关联。键和映射值的类型可能不同。
  • 内部没有任何的排序,是无序的,这点和map的最大区别,map有序
  • unordered_map通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭
    代方面效率较低。
  • 同样也支持operator【】访问
  • 底层是哈希桶结构
  • 迭代器是单向的,因为底层结构

使用 

使用上和map可以说是基本类似了!除了迭代器

构造方式

	unordered_map<string, int> m;//无参构造
	unordered_map<string, int> m1(m);//拷贝构造
	unordered_map<string, int> m2(m1.begin(), m1.end());//迭代器区间构造

	//初始化列表构造
	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };

修改 

insert向容器中插入键值对
erase删除键值对
clear清空元素
swap交换两个容器内容
	unordered_map<int, int> m;//无参构造
	vector<int> a = {3,6,9,4,2,10};
	for (auto b : a)
	{
		m.insert({ b,b });
	}
	m.erase(3);
	unordered_map<int, int> m1;
	m.swap(m1);

	m.clear();

容量

	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };
	m3.empty();//判空
	m3.size();//大小

迭代器

begin()返回第一个元素的迭代器
end()返回最后一个元素的下一个位置的迭代器
cbegin()返回第一个元素的const迭代器
cend()返回最后一个元素的下一个位置的const迭代器
	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };
	auto it = m3.begin();
	while (it!=m3.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}

 注意:这个系列只提供单向迭代器!!

元素访问

operator【】:返回key对应的value的引用,和map一样!功能强大,既能插入又能修改!

	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };
	m3["aa"] = 4;

查询

iterator find ( const key_type& k )放回key在哈希桶的位置
size_type count ( const key_type& k ) const;返回哈希桶中关键码为key的个数

注意:Key是唯一的,不允许重复,所以count为0/1!

	auto it = m3.find("aa");
	m3.count("aa");

桶操作 

bucket_count()返回桶的个数
bucket_size(n)返回n号桶中有效元素的总个数
bucket(key)返回元素key所在的桶号

二、unordered_set

介绍

  • unordered_set是存储key的关联式容器,K模型,底层可以看出<key,key>
  • 键值key通常用于惟一地标识元素(不存在相同元素)
  • 内部没有任何的排序,是无序的,这点和set的最大区别,set有序
  • unordered_set通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭
    代方面效率较低。
  • 底层是哈希桶结构
  • 迭代器是单向的,因为底层结构

使用

构造

和set基本一样,这里直接看实例就好了!

	unordered_set<int> s;//无参
	unordered_set<int> s1(s);//拷贝

	vector<int> a = { 3,6,9,4,2,10,3 };
	unordered_set<int> s2(a.begin(),a.end());//迭代区间
	//初始化列表
	unordered_set<int> s3 = { 6,7,1,2,4,9,10 };

修改

	unordered_set<int> m;//无参构造
	vector<int> a = {3,6,9,4,2,10};
	for (auto b : a)
	{
		m.insert(b);
	}
	m.erase(3);
	unordered_set<int> m1;
	m.swap(m1);
	m.clear();

容量

	unordered_set<int> s3 = { 3,6,9,4,2,10,3 };
	s3.size();
	s3.empty();

 迭代器(只有单向)

	unordered_set<int> s3 = { 3,6,9,4,2,10,3 };
	auto it = s3.begin();
	while (it != s3.end())
	{
		cout << *it << endl;
		++it;
	}

查询

auto it = s3.find(3);
s3.count(3);// 0/1

桶操作 

bucket_count()返回桶的个数
bucket_size(n)返回n号桶中有效元素的总个数
bucket(key)返回元素key所在的桶号
	cout << s3.bucket_count() << endl;//统计桶的总数
	cout << s3.bucket_size(3) << endl;//返回3号桶中的数据个数
	cout << s3.bucket(3) << endl;//放回3所在的桶号

注意:还有两个容器这里就不过多介绍了,这几个容器使用起来差别不算很大,也比较简单,大家可以点击unordered_multiset和unordered_multimap查看,区别就是multi系列可以存在重复元素

三、unordered系列的性能测试

void test_set2()
{
	const size_t N = 1000000;
	unordered_set<int> us;
	set<int> s;

	vector<int> v;
	v.reserve(N);
	srand(time(0));
	for (size_t i = 0; i < N; ++i)
	{
		//v.push_back(rand()); // N比较大时,重复值比较多
		//v.push_back(rand()+i); // 重复值相对少
		v.push_back(i); // 没有重复,有序
	}

	size_t begin1 = clock();
	for (auto e : v)
	{
		s.insert(e);
	}
	size_t end1 = clock();
	cout << "set insert:" << end1 - begin1 << endl;

	size_t begin2 = clock();
	for (auto e : v)
	{
		us.insert(e);
	}
	size_t end2 = clock();
	cout << "unordered_set insert:" << end2 - begin2 << endl;

	int m1 = 0;
	size_t begin3 = clock();
	for (auto e : v)
	{
		auto ret = s.find(e);
		if (ret != s.end())
		{
			++m1;
		}
	}
	size_t end3 = clock();
	cout << "set find:" << end3 - begin3 << "->" << m1 << endl;

	int m2 = 0;
	size_t begin4 = clock();
	for (auto e : v)
	{
		auto ret = us.find(e);
		if (ret != us.end())
		{
			++m2;
		}
	}
	size_t end4 = clock();
	cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << endl;

	cout << "插入数据个数:" << s.size() << endl;
	cout << "插入数据个数:" << us.size() << endl << endl;

	size_t begin5 = clock();
	for (auto e : v)
	{
		s.erase(e);
	}
	size_t end5 = clock();
	cout << "set erase:" << end5 - begin5 << endl;

	size_t begin6 = clock();
	for (auto e : v)
	{
		us.erase(e);
	}
	size_t end6 = clock();
	cout << "unordered_set erase:" << end6 - begin6 << endl << endl;

}

int main()
{
	test_set2();
	//test_map1();
	return 0;
}

大家可以copy到自己的编译器看看其他不同的结果,上述代码的结果如下:

可以看到unordered系列查找的速度确实快啊!因为底层的结构。


如果对你有那么一点帮助,欢迎点赞+收藏哦!


http://www.kler.cn/a/283983.html

相关文章:

  • ManiSkill学习笔记
  • 第二十周学习周报
  • Logrus入门
  • pyspark入门基础详细讲解
  • 并查集算法实现
  • 树与二叉树(李春葆课后习题代码题)
  • linux驱动--中断等待队列
  • 在docker镜像中使用java生成图片,图片中文字乱码,将文件存入虚拟机,然后打压缩包,文件名乱码
  • LLaMA-Factory微调入门个人重制版
  • 基于Python的热门旅游景点数据分析系统【python-爬虫-大数据定制】
  • axios取消请求CancelToken的原理解析及用法示例
  • C语言练习题 包含min函数的栈
  • EmguCV学习笔记 VB.Net 8.2 分水岭法 watershed
  • 谈谈 Python 可迭代对象的实现
  • udp可靠传输中ACK与NACK的选择
  • Memcached stats sizes 命令
  • OS库学习之rename(函数)
  • python数据分析——网络爬虫和API
  • 图灵盾IOS SDK
  • 数据结构之拓扑排序
  • 【王树森】RNN模型与NLP应用(6/9):Text Generation(个人向笔记)
  • 【C#】属性的声明
  • Elasticsearch中修改mapping的字段类型该怎么操作
  • Go语言结构快速说明
  • JAVA后端框架--【Mybatis】
  • 【单片机原理及应用】实验:数字秒表显示器