【c++】map&set
1、概念、场景
在C++中,map
和set
是标准库中提供的两个重要的关联容器。
1.1 map
map
: map
是一种键-值对的容器,它将键与值进行关联。每个键只能在map
中出现一次,而值则可以重复。map
中的元素按照键的顺序进行排序,并且可以通过键快速访问对应的值。
1.2 set
set
: set
是一种集合容器,它存储唯一的元素,并按照特定的排序规则进行排序。与map
不同,set
中的元素没有对应的值,只有键值本身。set
中的元素是唯一的,重复插入相同的键值只会保留一个。
1.3 场景
map
和set
有各自的使用场景:
map
的使用场景:- 关联数据存储:
map
适用于需要将键与值进行关联的情况。例如,存储学生的学号和姓名、货物的编号和名称等。 - 快速查找:
map
中的元素按照键的顺序进行排序,这使得在给定键的情况下能够快速查找对应的值。它提供了operator[]
用于访问和修改值,并且支持快速的查找、插入和删除操作。
- 关联数据存储:
set
的使用场景:- 存储唯一值:
set
存储的元素是唯一的,它会自动去重。如果你需要存储一组唯一的值,并且对值的顺序没有特殊要求,set
是一个很好的选择。 - 查找和存在性检查:由于
set
中的元素按照特定的排序规则进行排序,它提供了高效的查找和存在性检查。你可以使用find()
函数来查找特定的值,或者使用count()
函数来判断值是否存在于set
中。
- 存储唯一值:
需要注意的是,map
和set
都基于红黑树实现,这使得它们在大多数操作的时间复杂度为O(log n),其中n是元素的数量。如果需要更高效的查找或插入操作,可以考虑使用unordered_map
和unordered_set
,它们基于哈希表实现,具有平均时间复杂度为O(1)的性能,但会占用更多的内存。
2、实现模型
map
和set
在C++标准库中的实现模型基于红黑树(Red-Black Tree)。
红黑树后续有单独文章介绍,此处不赘述。
3、map使用
map
是一种键-值对的关联容器,在C++中通过std::map
模板类来实现。下面是map
的基本使用方法:
基本用法
- 包含头文件: 首先,确保包含了
<map>
头文件。
#include <map>
- 创建
map
对象: 使用std::map
模板类创建一个map
对象,并指定键类型和值类型。
std::map<KeyType, ValueType> myMap;
其中,KeyType
是键的数据类型,ValueType
是值的数据类型。
- 插入元素: 可以使用
insert()
函数或使用下标运算符[]
插入元素。通过键值对的方式将键和值插入到map
中。
myMap.insert(std::make_pair(key, value));
// 或者
myMap[key] = value;
- 访问元素: 可以使用键访问对应的值。
ValueType value = myMap[key];
- 遍历元素: 可以使用迭代器来遍历
map
中的所有元素。
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
KeyType key = it->first;
ValueType value = it->second;
// 使用 key 和 value 进行操作
}
- 查找元素: 可以使用
find()
函数来查找指定键的元素。
auto it = myMap.find(key);
if (it != myMap.end()) {
// 找到了元素
ValueType value = it->second;
} else {
// 未找到元素
}
- 删除元素: 可以使用
erase()
函数来删除指定键的元素。
myMap.erase(key);
实例化
在C++中,std::map
可以使用多种构造函数进行实例化。以下是几种常见的构造函数形式:
-
默认构造函数:
std::map<KeyType, ValueType> myMap;
使用默认构造函数创建一个空的
map
对象,其中KeyType
是键的数据类型,ValueType
是值的数据类型。 -
范围构造函数:
std::map<KeyType, ValueType> myMap(first, last);
使用范围构造函数可以从指定范围内的键值对初始化
map
,其中first
和last
是表示范围的迭代器,指定了要复制到map
的键值对的起始和结束位置。 -
拷贝构造函数:
std::map<KeyType, ValueType> myMap(otherMap);
使用拷贝构造函数可以创建一个新的
map
对象,并使用另一个map
对象otherMap
的键值对来初始化新的map
。 -
移动构造函数:
std::map<KeyType, ValueType> myMap(std::move(otherMap));
使用移动构造函数可以创建一个新的
map
对象,并使用另一个map
对象otherMap
的键值对来初始化新的map
。原始的map
对象otherMap
将被有效地转移(移动)到新的map
对象中,原来的map
将为空。
这些构造函数提供了不同的初始化map
的方式,可以根据具体的需求选择适当的构造函数来创建map
对象。
以上是map
的基本用法,可以根据实际需求使用其他成员函数和操作符对map
进行操作。
记住,map
中的元素按照键的顺序进行排序,并且每个键只能在map
中出现一次,确保键的唯一性。
4、set使用
set
是一种存储唯一值的关联容器,在C++中通过std::set
模板类来实现。下面是set
的基本使用方法:
基本用法
- 包含头文件: 首先,确保包含了
<set>
头文件。
#include <set>
- 创建
set
对象: 使用std::set
模板类创建一个set
对象,并指定值类型。
std::set<ValueType> mySet;
其中,ValueType
是值的数据类型。
- 插入元素: 使用
insert()
函数插入元素到set
中。由于set
中的元素是唯一的,重复插入相同的值只会保留一个。
mySet.insert(value);
- 访问元素: 由于
set
中的元素是唯一的,不能直接使用下标运算符[]
来访问元素。可以通过迭代器来访问set
中的元素。
for (auto it = mySet.begin(); it != mySet.end(); ++it) {
ValueType value = *it;
// 使用 value 进行操作
}
- 查找元素: 可以使用
find()
函数来查找指定值的元素。
auto it = mySet.find(value);
if (it != mySet.end()) {
// 找到了元素
ValueType value = *it;
} else {
// 未找到元素
}
- 删除元素: 可以使用
erase()
函数来删除指定值的元素。
mySet.erase(value);
实例化
在C++中,std::set
可以使用多种构造函数进行实例化。以下是几种常见的构造函数形式:
-
默认构造函数:
std::set<ValueType> mySet;
使用默认构造函数创建一个空的
set
对象,其中ValueType
是要存储在set
中的值的数据类型。 -
范围构造函数:
std::set<ValueType> mySet(first, last);
使用范围构造函数可以从指定范围内的元素初始化
set
,其中first
和last
是表示范围的迭代器,指定了要复制到set
的元素的起始和结束位置。 -
拷贝构造函数:
std::set<ValueType> mySet(otherSet);
使用拷贝构造函数可以创建一个新的
set
对象,并使用另一个set
对象otherSet
的元素来初始化新的set
。 -
移动构造函数:
std::set<ValueType> mySet(std::move(otherSet));
使用移动构造函数可以创建一个新的
set
对象,并使用另一个set
对象otherSet
的元素来初始化新的set
。原始的set
对象otherSet
将被有效地转移(移动)到新的set
对象中,原来的set
将为空。
这些构造函数提供了不同的初始化set
的方式,可以根据具体的需求选择适当的构造函数来创建set
对象。
以上是set
的基本用法,可以根据实际需求使用其他成员函数和操作符对set
进行操作。
set
中的元素会按照特定的排序规则进行排序,并且保持唯一性。
注意,set
是只读的,无法直接修改元素的值,需要先删除旧值,再插入新值。