6.set观察器和操作成员函数
Observers
- key_comp(返回键的比较对象):
key_compare key_comp() const;
- 返回一个键的比较对象,用于比较容器中键的大小关系。
- value_comp(返回值的比较对象):
value_compare value_comp() const;
- 返回一个值的比较对象,用于比较容器中的值的大小关系。
Operations
- find(查找元素):
iterator find(const key_type& key);
- 返回一个迭代器,指向键等于给定键的元素。如果未找到元素,则返回指向容器末尾的迭代器
end()
。
- count(计算特定值的元素个数):
size_type count(const key_type& key);
- 返回具有指定值的元素个数。通常情况下,由于键是唯一的,结果将是0或1。
- lower_bound(返回下限迭代器):
iterator lower_bound(const key_type& key);
- 返回一个迭代器,指向第一个大于或等于给定键的元素位置。
- upper_bound(返回上限迭代器):
iterator upper_bound(const key_type& key);
- 返回一个迭代器,指向第一个大于给定键的元素位置。
- equal_range(获取相等元素的范围):
pair<iterator, iterator> equal_range(const key_type& key);
- 返回一个包含两个迭代器的
pair
,第一个迭代器指向第一个等于给定键的元素,第二个迭代器指向第一个大于给定键的元素。
示例:
#include <iostream> #include <set> int main() { std::set<int> mySet = {1, 2, 3, 4, 5}; // 使用 key_comp 获取键的比较对象 std::set<int>::key_compare keyComp = mySet.key_comp(); // 使用 value_comp 获取值的比较对象 std::set<int>::value_compare valueComp = mySet.value_comp(); // 查找元素 std::set<int>::iterator it = mySet.find(3); if (it != mySet.end()) { std::cout << "找到元素 3" << std::endl; } else { std::cout << "未找到元素 3" << std::endl; } // 计算特定值的元素个数 size_t count = mySet.count(4); std::cout << "值为 4 的元素个数: " << count << std::endl; // 获取下限迭代器 std::set<int>::iterator lower = mySet.lower_bound(2); std::cout << "下限迭代器指向大于或等于 2 的元素位置: " << *lower << std::endl; // 获取上限迭代器 std::set<int>::iterator upper = mySet.upper_bound(4); std::cout << "上限迭代器指向大于 4 的元素位置: " << *upper << std::endl; // 获取相等元素的范围 std::pair<std::set<int>::iterator, std::set<int>::iterator> range = mySet.equal_range(3); std::cout << "相等元素范围: [" << *(range.first) << ", " << *(range.second) << "]" << std::endl; return 0; }
7.set应用场景
#include <set> void TestSet() { // 用数组array中的元素构造set int array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4,6, 8, 0 }; set<int> s(array, array+sizeof(array)/sizeof(array)); cout << s.size() << endl; // 正向打印set中的元素,从打印结果中可以看出:set可去重 for (auto& e : s) cout << e << " "; cout << endl; // 使用迭代器逆向打印set中的元素 for (auto it = s.rbegin(); it != s.rend(); ++it) cout << *it << " "; cout << endl; // set中值为3的元素出现了几次 cout << s.count(3) << endl; }
set和multiset的区别
std::set
和 std::multiset
都是 C++ 标准库中的关联式容器,它们用于存储一组元素,且元素是按照一定的顺序排列的。然而,它们之间有一个关键的区别:
- 唯一性:
std::set
:std::set
中的元素是唯一的,不允许重复的元素存在。如果试图插入重复的元素,新元素将不会被插入。std::multiset
:std::multiset
允许存储重复的元素,可以插入多个具有相同键值的元素。
下面是更详细的比较:
- std::set:
- 元素是唯一的,不允许重复。
- 插入操作会检查元素是否已存在,如果已存在则插入不成功。
- 查找操作在
O(log n)
的时间内完成,因为元素唯一。 - 适用于需要维护一组唯一值的情况,例如去重操作。
- std::multiset:
- 允许存储重复的元素,不会检查重复性。
- 插入操作总是成功,允许存储多个相同键值的元素。
- 查找操作在
O(log n)
的时间内完成,因为仍然具有排序特性。 - 适用于需要允许重复值的情况,例如统计元素出现次数。
multiset
在底层实际存储的是<int, int>
的键值对。
在选择使用 std::set
还是 std::multiset
时,取决于你的数据需求。如果需要维护一组唯一的值,使用 std::set
;如果允许重复值,并且需要统计重复值的出现次数,使用 std::multiset
。
map
1.map模板参数列表
template < class Key, // map::key_type class T, // map::mapped_type class Compare = less<Key>, // map::key_compare class Alloc = allocator<pair<const Key,T> > // map::allocator_type > class map;
std::map
是一个关联式容器,它提供了key-value
对的存储和管理。以下是代码中各个模板参数的解释:
Key
:表示std::map
容器中的键类型,也就是键值对中的键的类型。T
:表示std::map
容器中的值类型,也就是键值对中的值的类型。Compare
:表示比较键的方式的函数对象,默认使用std::less<Key>
,可以根据需要自定义键的比较方式。Alloc
:表示用于分配内存的分配器类型,默认使用std::allocator<std::pair<const Key, T>>
,通常情况下不需要自定义。
通过这个模板声明,你可以创建不同类型的std::map
容器,以存储不同类型的key-value
对。例如,如果要创建一个存储整数键和字符串值的std::map
容器,可以这样使用:
std::map<int, std::string> myMap;
这将创建一个std::map
容器,其中键的类型是整数 (int
),值的类型是字符串 (std::string
)。您可以使用该容器来存储和检索整数和字符串之间的映射关系。
成员类型
2.map的构造
- empty(默认构造函数):
explicit map(const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());
- 这是
std::map
的默认构造函数,它创建一个空的std::map
对象。 comp
参数是可选的,表示用于比较键的自定义比较函数,默认使用key_compare()
,即使用std::less<Key>
。alloc
参数是可选的,表示用于内存分配的自定义分配器,默认使用allocator_type()
,即使用std::allocator<std::pair<const Key, T>>
。
- range(范围构造函数):
template <class InputIterator> map(InputIterator first, InputIterator last, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());
- 这个构造函数允许您从一个范围(由迭代器
first
和last
定义)初始化std::map
容器。 comp
参数是可选的,表示用于比较键的自定义比较函数,默认使用key_compare()
。alloc
参数是可选的,表示用于内存分配的自定义分配器,默认使用allocator_type()
。
- copy(复制构造函数):
map(const map& x);
- 这个构造函数用于创建一个新的
std::map
容器,并以另一个std::map
容器x
的内容进行初始化,即复制x
中的键值对到新的容器中。
示例:
#include <iostream> #include <map> int main() { // 使用默认构造函数创建一个空的 std::map std::map<int, std::string> myMap1; // 使用范围构造函数创建并初始化 std::map std::map<int, std::string> myMap2 = {{1, "One"}, {2, "Two"}, {3, "Three"}}; // 使用复制构造函数创建一个与 myMap2 相同内容的副本 std::map<int, std::string> myMap3(myMap2); // 输出容器内容 std::cout << "myMap1: " << myMap1.size() << " elements" << std::endl; std::cout << "myMap2: " << myMap2.size() << " elements" << std::endl; std::cout << "myMap3: " << myMap3.size() << " elements" << std::endl; return 0; }
在此示例中,我们演示了三种不同的std::map
构造函数的使用方式,包括默认构造函数、范围构造函数和复制构造函数。根据构造函数的不同用途,可以创建空容器、初始化容器或复制另一个容器的内容。
赋值运算符重载
将一个 std::map
的内容复制到另一个已存在的 std::map
中。例如:
std::map<int, std::string> sourceMap = {{1, "One"}, {2, "Two"}}; std::map<int, std::string> targetMap; targetMap = sourceMap; // 使用拷贝赋值运算符将内容复制到目标容器
它会创建一个新的 std::map
容器,其中包含与原始容器相同的键值对。这是一种将数据从一个容器复制到另一个容器的常见方式。
3.map迭代器
std::map
容器提供了多种迭代器,用于访问容器中的元素。以下是这些迭代器的详细描述:
- begin:
iterator begin();
- 返回一个迭代器,指向
std::map
容器中第一个元素的位置。
- end:
iterator end();
- 返回一个迭代器,指向
std::map
容器中的末尾(尾后位置)。
- rbegin:
reverse_iterator rbegin();
- 返回一个逆向迭代器,指向
std::map
容器中的最后一个元素的位置。
- rend:
reverse_iterator rend();
- 返回一个逆向迭代器,指向
std::map
容器中的逆向末尾(逆向尾后位置)。
- cbegin:
const_iterator cbegin() const;
- 返回一个常量迭代器,指向
std::map
容器中第一个元素的位置。用于只读访问。
- cend:
const_iterator cend() const;
- 返回一个常量迭代器,指向
std::map
容器中的末尾(尾后位置)。用于只读访问。
- crbegin:
const_reverse_iterator crbegin() const;
- 返回一个常量逆向迭代器,指向
std::map
容器中的最后一个元素的位置。用于只读访问。
- crend:
const_reverse_iterator crend() const;
- 返回一个常量逆向迭代器,指向
std::map
容器中的逆向末尾(逆向尾后位置)。用于只读访问。
示例:
#include <iostream> #include <map> int main() { // 创建一个 std::map 容器并初始化 std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}}; // 使用正向迭代器遍历容器 std::cout << "正向迭代器遍历容器:" << std::endl; for (std::map<int, std::string>::iterator it = myMap.begin(); it != myMap.end(); ++it) { std::cout << "键: " << it->first << ", 值: " << it->second << std::endl; } // 使用逆向迭代器遍历容器 std::cout << "逆向迭代器遍历容器:" << std::endl; for (std::map<int, std::string>::reverse_iterator rit = myMap.rbegin(); rit != myMap.rend(); ++rit) { std::cout << "键: " << rit->first << ", 值: " << rit->second << std::endl; } // 使用常量迭代器遍历容器(只读访问) std::cout << "常量迭代器遍历容器:" << std::endl; for (std::map<int, std::string>::const_iterator cit = myMap.cbegin(); cit != myMap.cend(); ++cit) { std::cout << "键: " << cit->first << ", 值: " << cit->second << std::endl; } // 使用常量逆向迭代器遍历容器(只读访问) std::cout << "常量逆向迭代器遍历容器:" << std::endl; for (std::map<int, std::string>::const_reverse_iterator crit = myMap.crbegin(); crit != myMap.crend(); ++crit) { std::cout << "键: " << crit->first << ", 值: " << crit->second << std::endl; } return 0; }
这个示例演示了如何使用不同类型的迭代器遍历std::map
容器中的元素:
- 使用正向迭代器
begin()
和end()
遍历容器。 - 使用逆向迭代器
rbegin()
和rend()
逆向遍历容器。 - 使用常量迭代器
cbegin()
和cend()
以只读方式遍历容器。 - 使用常量逆向迭代器
crbegin()
和crend()
以只读方式逆向遍历容器。
4.map容量和元素访问函数
这些是关于std::map
容器的一些容量和元素访问相关的成员函数:
- empty(检查是否为空):
bool empty() const;
- 用于检查
std::map
容器是否为空。如果容器为空,返回true
;否则返回false
。
- size(返回容器大小):
size_type size() const;
- 返回
std::map
容器中键值对的数量,也就是容器的大小。
- max_size(返回最大容量):
size_type max_size() const;
- 返回
std::map
容器可以容纳的最大元素数量。这通常受到系统内存限制的影响。
- operator[](访问元素):
T& operator[](const key_type& key);
- 允许通过键访问容器中的元素。如果键存在,则返回相应的值的引用,如果不存在,则会插入一个具有该键的默认值,并返回引用。请注意,如果键不存在,将插入一个具有默认值的键值对。
- at(访问元素):
T& at(const key_type& key);
- 允许通过键访问容器中的元素,类似于
operator[]
。但与operator[]
不同,如果键不存在,at
会抛出std::out_of_range
异常。
示例:
#include <iostream> #include <map> int main() { std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}}; // 检查容器是否为空 if (myMap.empty()) { std::cout << "容器为空" << std::endl; } else { std::cout << "容器不为空" << std::endl; } // 获取容器的大小 std::cout << "容器大小为: " << myMap.size() << std::endl; // 访问容器中的元素 std::string value = myMap[2]; // 使用 operator[] std::cout << "键 2 对应的值为: " << value << std::endl; try { std::string value = myMap.at(4); // 键 4 不存在,会抛出异常 } catch (const std::out_of_range& e) { std::cerr << "键 4 不存在: " << e.what() << std::endl; } return 0; }
在此示例中,我们演示了如何使用std::map
容器的容量和元素访问成员函数,包括检查容器是否为空、获取容器大小、通过键访问元素以及处理键不存在的情况。
5.map修改器函数
- insert(插入元素):
pair<iterator, bool> insert(const value_type& value);
- 用于插入键值对(键值对的类型为
value_type
)到std::map
容器中。如果插入成功,返回一个迭代器指向插入的元素和true
;如果元素已存在,则返回一个迭代器指向现有元素和false
。
- erase(删除元素):
iterator erase(iterator position);
size_type erase(const key_type& key);
- 用于删除容器中的元素。第一种形式删除由迭代器
position
指定的元素,并返回指向下一个元素的迭代器。第二种形式删除指定键的元素,并返回删除的元素数量。
- swap(交换内容):
void swap(map& x);
- 用于交换两个
std::map
容器的内容,即交换键值对。交换后,两个容器的内容完全交换。
- clear(清空内容):
void clear();
- 用于清空
std::map
容器中的所有元素,使容器成为空容器。
- emplace(构造并插入元素):
pair<iterator, bool> emplace(Args&&... args);
- 允许构造并插入元素,其中
Args
是键值对的构造参数。如果插入成功,返回一个迭代器指向插入的元素和true
;如果元素已存在,则返回一个迭代器指向现有元素和false
。
- emplace_hint(构造并插入元素带提示):
iterator emplace_hint(const_iterator position, Args&&... args);
- 允许构造并插入元素,其中
Args
是键值对的构造参数,并且可以提供插入位置的提示。返回一个迭代器指向插入的元素。
示例:
#include <iostream> #include <map> int main() { std::map<int, std::string> myMap; // 插入元素 myMap.insert(std::make_pair(1, "One")); myMap.insert(std::make_pair(2, "Two")); // 删除元素 myMap.erase(2); // 交换容器内容 std::map<int, std::string> anotherMap = {{3, "Three"}, {4, "Four"}}; myMap.swap(anotherMap); // 清空容器 myMap.clear(); // 构造并插入元素 myMap.emplace(5, "Five"); // 使用 emplace_hint 插入元素 std::map<int, std::string>::iterator it = myMap.emplace_hint(myMap.begin(), 6, "Six"); // 输出容器内容 for (const auto& pair : myMap) { std::cout << "键: " << pair.first << ", 值: " << pair.second << std::endl; } return 0; }
在此示例中,我们演示了如何使用std::map
容器的修改器成员函数,包括插入、删除、交换和清空元素,以及使用 emplace
和 emplace_hint
插入元素的方式。
6.map观察器和操作成员函数
Observers
- key_comp(返回键的比较对象):
key_compare key_comp() const;
- 返回一个键的比较对象,用于比较容器中键的大小关系。
- value_comp(返回值的比较对象):
value_compare value_comp() const;
- 返回一个值的比较对象,用于比较容器中的值的大小关系。
Operations
- find(查找元素):
iterator find(const key_type& key);
- 返回一个迭代器,指向键等于给定键的元素。如果未找到元素,则返回指向容器末尾的迭代器
end()
。
- count(计算特定键的元素个数):
size_type count(const key_type& key);
- 返回具有指定键的元素个数。通常情况下,由于键是唯一的,结果将是0或1。
- lower_bound(返回下限迭代器):
iterator lower_bound(const key_type& key);
- 返回一个迭代器,指向第一个大于或等于给定键的元素位置。
- upper_bound(返回上限迭代器):
iterator upper_bound(const key_type& key);
- 返回一个迭代器,指向第一个大于给定键的元素位置。
- equal_range(获取相等元素的范围):
pair<iterator, iterator> equal_range(const key_type& key);
- 返回一个包含两个迭代器的
pair
,第一个迭代器指向第一个等于给定键的元素,第二个迭代器指向第一个大于给定键的元素。
以下是示例用法:
#include <iostream> #include <map> int main() { std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}}; // 使用 find 查找元素 std::map<int, std::string>::iterator it = myMap.find(2); if (it != myMap.end()) { std::cout << "找到键 2,值为: " << it->second << std::endl; } else { std::cout << "未找到键 2" << std::endl; } // 使用 count 计算特定键的元素个数 size_t count = myMap.count(3); std::cout << "键 3 的元素个数: " << count << std::endl; // 使用 lower_bound 获取下限迭代器 std::map<int, std::string>::iterator lower = myMap.lower_bound(2); std::cout << "下限迭代器指向键 2,值为: " << lower->second << std::endl; // 使用 upper_bound 获取上限迭代器 std::map<int, std::string>::iterator upper = myMap.upper_bound(2); std::cout << "上限迭代器指向大于键 2 的元素,值为: " << upper->second << std::endl; // 使用 equal_range 获取相等元素的范围 std::pair<std::map<int, std::string>::iterator, std::map<int, std::string>::iterator> range = myMap.equal_range(2); std::cout << "相等元素范围: [" << range.first->second << ", " << range.second->second << "]" << std::endl; return 0; }
在此示例中,我们演示了如何使用std::map
容器的观察器和操作成员函数,包括查找元素、计算特定键的元素个数、获取下限迭代器、获取上限迭代器以及获取相等元素的范围。这些函数使得在std::map
容器中执行查找和搜索操作变得非常方便。
7.map应用场景
#include <string> #include <map> void TestMap() { map<string, string> m; // 向map中插入元素的方式: // 将键值对<"peach","桃子">插入map中,用pair直接来构造键值对 m.insert(pair<string, string>("peach", "桃子")); // 将键值对<"peach","桃子">插入map中,用make_pair函数来构造键值对 m.insert(make_pair("banan", "香蕉")); // 借用operator[]向map中插入元素 /* operator[]的原理是: 用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中 如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器 如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器 operator[]函数最后将insert返回值键值对中的value返回 */ // 将<"apple", "">插入map中,插入成功,返回value的引用,将“苹果”赋值给该引用结果, m["apple"] = "苹果"; // key不存在时抛异常 //m.at("waterme") = "水蜜桃"; cout << m.size() << endl; // 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列 for (auto& e : m) cout << e.first << "--->" << e.second << endl; cout << endl; // map中的键值对key一定是唯一的,如果key存在将插入失败 auto ret = m.insert(make_pair("peach", "桃色")); if (ret.second) cout << "<peach, 桃色>不在map中, 已经插入" << endl; else cout << "键值为peach的元素已经存在:" << ret.first->first << "--->" << ret.first->second << " 插入失败" << endl; // 删除key为"apple"的元素 m.erase("apple"); if (1 == m.count("apple")) cout << "apple还在" << endl; else cout << "apple被吃了" << endl; }
map和multimap的区别
std::map
和 std::multimap
都是 C++ 标准库中的关联式容器,它们用于存储一组key-value
对(键值对),并根据键对元素进行排序。它们之间的主要区别在于唯一性和允许重复性:
std::map:
std::map
是一个关联容器,其中的键是唯一的,每个键只能关联一个值。- 如果试图插入已存在的键,新值将覆盖旧值。
- 使用
operator[]
或insert
插入元素。 - 查找操作(例如
find
、count
、lower_bound
、upper_bound
)返回匹配的唯一元素。
std::multimap:
std::multimap
也是一个关联容器,允许多个具有相同键的值存在。- 可以插入多个具有相同键的值,不会覆盖旧值。
- 使用
insert
插入元素。 - 查找操作返回匹配的所有元素,因为可以有多个相同键的元素。
以下是示例用法和比较:
std::map 示例:
#include <iostream> #include <map> int main() { std::map<int, std::string> myMap; // 插入键值对 myMap[1] = "One"; myMap[2] = "Two"; myMap[3] = "Three"; // 重复键值对将覆盖旧值 myMap[2] = "New Two"; // 查找键为 2 的元素 std::map<int, std::string>::iterator it = myMap.find(2); if (it != myMap.end()) { std::cout << "找到键 2,值为: " << it->second << std::endl; } return 0; }
std::multimap 示例:
#include <iostream> #include <map> int main() { std::multimap<int, std::string> myMultiMap; // 插入多个具有相同键的值 myMultiMap.insert(std::make_pair(1, "One")); myMultiMap.insert(std::make_pair(2, "Two")); myMultiMap.insert(std::make_pair(2, "Another Two")); myMultiMap.insert(std::make_pair(3, "Three")); // 查找键为 2 的所有元素 auto range = myMultiMap.equal_range(2); for (auto it = range.first; it != range.second; ++it) { std::cout << "找到键 2,值为: " << it->second << std::endl; } return 0; }
总结:
- 如果需要维护唯一
key-value
对,使用std::map
。 - 如果允许具有相同键的多个值存在,使用
std::multimap
。