C++必修:unordered_set/unordered_map

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C++学习
贝蒂的主页:Betty’s blog

1. unordered_set的介绍

unordered_set是一种关联式容器,它具有以下几个特点:

  1. 基本概念
  • unordered_set是一种关联式容器,不按特定顺序存储键值。
  • 元素的值同时也是唯一标识它的key
  1. 内部存储方式
  • 内部元素没有按照特定顺序排序。
  • 为快速找到指定key,将相同哈希值的键值放在相同的桶中(开散列)。
  1. 性能特点
  • 通过key访问单个元素比set快。
  • 在遍历元素子集的范围迭代方面效率较低,因为数据并不在某个范围,而是无序的。
  1. 迭代器类型
  • 迭代器至少是前向迭代器。

具体可参考官方文档——unordered_set

2. unordered_set的功能

首先unordered_setSTL其他大多数容器一样,为了支持所有类型,所以是一个类模版。

2.1 unordered_set的初始化

unordered_set初始化会调用构造函数,其构造函数分别重载了以下几种方式:
image.png

void Test1()
{
	//1.默认无参构造
	unordered_set<int> s1;
	//2.迭代器区间初始化
	string str("betty");
	unordered_set<char> s2(str.begin(), str.end());
	//3.拷贝构造
	unordered_set<int> s3(s1);
}

2.2 unordered_set的迭代器

成员函数功能
begin获取容器中第一个元素的迭代器
end获取容器中最后一个元素下一个位置的正向迭代器

一般而言unordered_set并不支持反向迭代器,其次这些函数与其他容器的迭代器成员函数无论是功能还是用法都是一模一样的,所以上手可谓十分简单。

void Test2()
{
	vector<int> arr = { 1,2,3,4,5,6,7 };
	//迭代器区间初始化
	unordered_set<int> s1(arr.begin(), arr.end());
	//正向迭代器
	unordered_set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

image.png

2.3 unordered_set的常见成员函数

以下是unordered_set常见的成员函数:

成员函数功能
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
empty判断容器是否为空
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数
void Test3()
{
	unordered_set<int> s1;
	//插入元素并去重
	s1.insert(1);
	s1.insert(2);
	s1.insert(2);
	s1.insert(3);
	s1.insert(3);
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl; 
	unordered_set<int>::iterator it = s1.find(1);
	//如果找不到返回end()
	if (it != s1.end())
	{
		s1.erase(1);
	}
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	//容器中值为2的元素个数
	cout <<"容器中值为2的元素个数"<< s1.count(2) << endl;
}

image.png

void Test4()
{
	unordered_set<int> s1;
	s1.insert(1);
	s1.insert(2);
	s1.insert(3);
	//容器大小
	cout << s1.size() << endl;
	//清空容器
	s1.clear();
	//容器判空
	cout << s1.empty() << endl;
	vector<int> arr = { 1,2,3,4,5,6,7 };
	//迭代器区间初始化
	unordered_set<int> tmp(arr.begin(), arr.end());
	//交换两个容器的数据
	s1.swap(tmp);
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
}

image.png
值得注意的是:unordered_set的插入与删除操作可能存在迭代器失效的问题。

3. unordered_multiset

unordered_multiset的使用方式与unordered_set基本一致,唯一的区别就在于unordered_multiset允许键值冗余,即可存储重复元素。

void Test5()
{
	unordered_multiset<int> s1;
	//支持键值冗余
	s1.insert(1);
	s1.insert(1);
	s1.insert(2);
	s1.insert(2);
	s1.insert(3);
	s1.insert(4);
	unordered_multiset<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
}

image.png
值得注意的是:unordered_multisetfind返回返回底层哈希表中第一个找到的键值为val的元素的迭代器

4. unordered_map的介绍

unordered_map 是 C++ 中的关联式容器,具有以下特性:

  1. unordered_map 定义
  • unordered_map是存储<key, value>键值对的关联式容器,允许通过keys快速索引与其对应的 value
  1. 键值与映射值
  • 键值通常用于唯一标识元素,映射值是与键关联的对象,键和映射值类型可能不同。
  1. 内部存储结构
  • 内部不对<key, value>按照特定顺序排序,将相同哈希值的键值对放在相同桶中(开散列),以便在常数范围内找到key对应的value
  1. 访问效率
  • 通过key访问单个元素比map快,但在遍历元素子集的范围迭代方面效率较低。
  1. 访问操作符
  • 实现了直接访问操作符operator[],允许用key作为参数直接访问value
  1. 迭代器类型
  • 迭代器至少是前向迭代器。

具体可参考官方文档——unordered_map

5. unordered_map 的功能

首先unordered_map 同样与STL其他大多数容器一样,为了支持所有类型,所以是一个类模版。

5.1 unordered_map的初始化

unordered_map初始化会调用构造函数,其构造函数分别重载了以下几种方式:
image.png

void Test6()
{
	//1.默认无参构造
	unordered_map<int, int> m1;
	//2.迭代器区间初始化
	unordered_map<int, int> m2(m1.begin(), m1.end());
	//3.拷贝构造
	unordered_map<int, int> m3(m1);
}

5.2 unordered_map的迭代器

成员函数功能
begin获取容器中第一个元素的迭代器
end获取容器中最后一个元素下一个位置的正向迭代器

一般而言unordered_map并不支持反向迭代器,其次这些函数也与其他容器的迭代器成员函数无论是功能还是用法都是一模一样的,所以上手可谓十分简单。

void Test7()
{
	unordered_map<int, string> m;
	m.insert(pair<int, string>(1, "one"));
	m.insert(pair<int, string>(2, "two"));
	m.insert(pair<int, string>(3, "three"));
	//正向迭代器
	unordered_map<int, string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
}

image.png

5.3 unordered_map的常见成员函数

unordered_mapunordered_set的成员函数类似,只不过多了一个[]运算符重载。

成员函数功能
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
empty判断容器是否为空
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数
[]运算符重载返回key所对应的val
void Test8()
{
	unordered_map<int,string> m1;
	//插入元素并去重
	m1.insert(make_pair(1,"one"));
	m1.insert(make_pair(1,"one"));
	m1.insert(make_pair(2, "two"));
	m1.insert(make_pair(2, "two"));
	m1.insert(make_pair(3, "three"));
	m1.insert(make_pair(3, "three"));
	unordered_map<int, string>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
	it = m1.find(1);
	//如果找不到返回end()
	if (it != m1.end())
	{
		m1.erase(1);
	}
	it = m1.begin();
	while (it != m1.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
	//容器中值为2的元素个数
	cout << "容器中值为2的元素个数" << m1.count(2) << endl;
}

image.png

void Test9()
{
	unordered_map<int,string> m1;
	m1.insert(pair<int, string>(1, "one"));
	m1.insert(pair<int, string>(2, "two"));
	m1.insert(pair<int, string>(3, "three"));
	//容器大小
	cout << m1.size() << endl;
	//清空容器
	m1.clear();
	//容器判空
	cout << m1.empty() << endl;
	unordered_map<int, string> tmp;
	tmp.insert(pair<int, string>(4, "four"));
	tmp.insert(pair<int, string>(5, "five"));
	tmp.insert(pair<int, string>(6, "six"));
	//交换两个容器的数据
	m1.swap(tmp);
	unordered_map<int, string>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
}

image.png
值得注意的是:unordered_map的插入与删除操作可能存在迭代器失效的问题。

6. unordered_multimap

unordered_multimap的使用方式与unordered_map基本一致,唯一的区别就在于unordered_multimap允许键值冗余,即可存储重复元素。

void Test9()
{
	//允许键值冗余
	unordered_multimap<int, string> m;
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(1, "1"));
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(2, "2"));
	m.insert(make_pair(3, "three"));
	for (auto e : m)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
	cout << endl; 
}

image.png
值得注意的是:unordered_multimapfind返回底层哈希表中第一个找到的键值为key的键值对的迭代器,而unordered_map返回的是key元素的迭代器。并且由于unordered_multimap支持键值冗余,所以其成员函数没有[]运算符重载,因为一旦键值容易,根本不知道该返回哪个键值的value

思考题:为什么unordered_map/unordered_set存在迭代器失效的问题,而map/set就没有呢?

其实这种说法并不准确,因为unordered_map/unordered_set通常是基于哈希表实现,哈希表插入或删除时可能需要移动桶中的元素(扩容)或重新链接元素(扩容或删除桶中元素),这个操作会导致指向这些桶的迭代器失效。而map/set通常基于红黑树实现,红黑树的删除操作只涉及树节点的重新链接和旋转,不影响其他节点的内存位置。所以插入/删除操作不会导致对其他节点迭代器失效(但是指向该删除节点的迭代器是失效的)。

unordered_set和unordered_mapC++标准库中的容器,用于存储和管理不重复的元素集合和键值对集合。 unordered_set是一个无序的集合容器,其中的元素是唯一的且无序的。它基于哈希表实现,因此插入、删除和查找操作的平均时间复杂度为常数时间O(1)。使用unordered_set可以快速判断一个元素是否存在于集合中。 unordered_map是一个无序的键值对容器,其中的键是唯一的且无序的。它也基于哈希表实现,因此插入、删除和查找操作的平均时间复杂度为常数时间O(1)。使用unordered_map可以根据键快速查找对应的值。 使用unordered_set和unordered_map时,需要包含头文件<unordered_set>和<unordered_map>。以下是它们的基本用法: 1. 创建容器: unordered_set<int> mySet; // 创建一个空的unordered_set unordered_map<string, int> myMap; // 创建一个空的unordered_map 2. 插入元素或键值对: mySet.insert(10); // 插入元素10到unordered_set中 myMap["apple"] = 5; // 插入键值对("apple", 5)到unordered_map中 3. 删除元素或键值对: mySet.erase(10); // 从unordered_set中删除元素10 myMap.erase("apple"); // 从unordered_map中删除键为"apple"的键值对 4. 查找元素或键值对: auto it = mySet.find(10); // 在unordered_set中查找元素10,返回迭代器 if (it != mySet.end()) { // 找到了元素 } auto it = myMap.find("apple"); // 在unordered_map中查找键为"apple"的键值对,返回迭代器 if (it != myMap.end()) { // 找到了键值对 int value = it->second; // 获取对应的值 }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Betty’s Sweet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值