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

关联式容器——map与set

map与set

  • map与set的使用
    • 序列式容器与关联式容器概念
      • 序列式容器 (Sequence Containers)
        • 常见的序列式容器:
      • 关联式容器 (Associative Containers)
        • 常见的关联式容器:
    • set的定义与使用
      • set类的介绍
      • set的构造和迭代器
      • set的增删查(无改)
    • map的定义与使用
      • map的介绍
      • pair类型介绍
      • map的构造函数与迭代器
      • map的增删查

map与set的使用

序列式容器与关联式容器概念

在 C++ 的标准模板库 (STL) 中,容器分为两大类:序列式容器关联式容器。这两类容器各自有不同的特点和用途。

序列式容器 (Sequence Containers)

序列式容器是按顺序存储元素的容器。它们通常保留元素的插入顺序,并且支持通过下标直接访问元素。序列式容器的主要特点包括:

  • 元素顺序:元素按照插入的顺序排列,可以通过索引访问。
  • 动态大小:可以根据需要动态调整大小。
  • 效率:在容器的末尾插入或删除元素通常是高效的。
常见的序列式容器:

vector

动态数组,支持随机访问。
可以高效地在末尾插入和删除元素。
在中间插入和删除元素时效率较低,因为需要移动元素。

deque(双端队列):

允许在两端快速插入和删除元素。
支持随机访问,但比 vector 稍慢。

list(双向链表):

允许在任意位置快速插入和删除元素。
不支持随机访问,但支持快速前后遍历。

forward_list(单向链表):

只支持前向遍历,内存占用较少。
提供快速的插入和删除。

array

固定大小的数组,支持快速随机访问。
不支持动态调整大小。

关联式容器 (Associative Containers)

关联式容器使用特定的规则(如键值对)来存储元素,通常不保留插入顺序。它们主要用于通过键快速查找值。关联式容器的主要特点包括:

  • 基于键值对:每个元素由键和值组成,通常通过键进行访问。
  • 自动排序:元素根据键进行排序,允许快速查找。
  • 效率:基于平衡树或哈希表实现,支持高效的查找、插入和删除。
常见的关联式容器:

set

存储唯一元素,并根据元素的值进行自动排序。
不允许重复元素,支持高效查找。

multiset

类似于 set,但允许重复元素。
也会自动排序。

map

存储键值对,每个键是唯一的,值可以重复。
根据键自动排序,支持通过键快速查找值。

multimap

类似于 map,但允许相同的键对应多个值。

总结

序列式容器:用于顺序存储和操作元素,适合需要保持插入顺序或随机访问的场景。

关联式容器:用于高效查找、插入和删除操作,适合需要基于键进行访问的场景。

set的定义与使用

set类的介绍

如图为官网的英文介绍
在这里插入图片描述

set的定义语法

template < class T,                        // set::key_type/value_typeclass Compare = less<T>,        // set::key_compare/value_compareclass Alloc = allocator<T>      // set::allocator_type> class set;
  • T就是set底层关键字的类型

  • set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数

  • set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参数。

  • ⼀般情况下,我们都不需要传后两个模版参数。

  • set底层是⽤红⿊树实现,增删查效率是 ,迭代器遍历是⾛的搜索树的中序,所以是有序的。

set的构造和迭代器

set的支持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是⼆叉搜索树,迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for,set的iterator和const_iterator都不⽀持迭代器修改数据,修改关键字数据,破坏了底层搜索树的结构。

ps:不允许修改数据

set的构造函数

//empty (1)	
explicit set (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
explicit set (const allocator_type& alloc);//range (2)	
template <class InputIterator>set (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type());//copy (3)	
set (const set& x);
set (const set& x, const allocator_type& alloc);//move (4)	
set (set&& x);
set (set&& x, const allocator_type& alloc);//initializer list (5)	
set (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
  1. 默认构造函数
    创建一个空的 set:
#include <set>std::set<int> mySet; // 创建一个空的 set
  1. 使用初始列表
    使用初始化列表直接创建 set:
#include <iostream>
#include <set>std::set<int> mySet = {5, 3, 8, 1}; // 创建并初始化for (const auto& elem : mySet) {std::cout << elem << " "; // 输出:1 3 5 8
}
  1. 使用范围构造函数
    从另一个容器(如 vector)复制元素:
#include <iostream>
#include <set>
#include <vector>std::vector<int> vec = {4, 2, 7, 1};
std::set<int> mySet(vec.begin(), vec.end()); // 从 vector 初始化for (const auto& elem : mySet) {std::cout << elem << " "; // 输出:1 2 4 7
}
  1. 使用比较函数的构造函数
    自定义比较规则(降序排列):
#include <iostream>
#include <set>struct Descending {bool operator()(int a, int b) const {return a > b;}
};std::set<int, Descending> mySet = {5, 3, 8, 1}; // 使用自定义比较for (const auto& elem : mySet) {std::cout << elem << " "; // 输出:8 5 3 1
}
  1. 复制构造函数
    复制已有的 set:
#include <iostream>
#include <set>std::set<int> originalSet = {1, 2, 3};
std::set<int> copiedSet(originalSet); // 复制构造for (const auto& elem : copiedSet) {std::cout << elem << " "; // 输出:1 2 3
}

迭代器

// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

set的增删查(无改)

函数介绍

// 单个数据插⼊,如果已经存在则插⼊失败
pair<iterator,bool> insert (const value_type& val);// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);// 查找val,返回val所在的迭代器,没有找到返回end()
iterator find (const value_type& val);// 查找val,返回Val的个数
size_type count (const value_type& val) const;// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);// 删除val,val不存在返回0,存在返回1
size_type erase (const value_type& val);// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);// 返回⼤于等val位置的迭代器
iterator lower_bound (const value_type& val) const;// 返回⼤于val位置的迭代器
iterator upper_bound (const value_type& val) const;

插入操作详解

  1. 基本插入
#include <iostream>
#include <set>int main() {std::set<int> mySet;// 插入元素mySet.insert(10);mySet.insert(20);mySet.insert(30);// 打印元素for (const auto& elem : mySet) {std::cout << elem << " ";}// 输出: 10 20 30return 0;
}
  1. 插入重复元素
    set 只存储唯一的元素,尝试插入重复元素时不会插入成功。
#include <iostream>
#include <set>int main() {std::set<int> mySet;mySet.insert(10);mySet.insert(20);mySet.insert(10); // 重复元素for (const auto& elem : mySet) {std::cout << elem << " ";}// 输出: 10 20return 0;
}
  1. 使用 insert 返回值
    insert 函数返回一个 pair,其中包含一个迭代器和一个布尔值,布尔值表示插入是否成功。
#include <iostream>
#include <set>int main() {std::set<int> mySet;auto result = mySet.insert(10);if (result.second) {std::cout << "插入成功: " << *result.first << std::endl;} else {std::cout << "插入失败: " << *result.first << std::endl;}result = mySet.insert(10); // 再次插入同样的元素if (result.second) {std::cout << "插入成功: " << *result.first << std::endl;} else {std::cout << "插入失败: " << *result.first << std::endl;}return 0;
}
  1. 插入多个元素
    可以使用 insert 函数直接插入一个范围的元素。
#include <iostream>
#include <set>
#include <vector>int main() {std::set<int> mySet;std::vector<int> vec = {1, 2, 3, 4, 5};// 插入整个范围mySet.insert(vec.begin(), vec.end());for (const auto& elem : mySet) {std::cout << elem << " ";}// 输出: 1 2 3 4 5return 0;
}
  1. 插入自定义对象
    如果要在 set 中存储自定义对象,需要重载 < 运算符。
#include <iostream>
#include <set>struct Person {std::string name;int age;// 重载小于运算符以进行比较bool operator<(const Person& other) const {return name < other.name; // 按名字排序}
};int main() {std::set<Person> people;people.insert({"Alice", 30});people.insert({"Bob", 25});people.insert({"Charlie", 20});for (const auto& person : people) {std::cout << person.name << " " << person.age << std::endl;}return 0;
}
  1. 处理空插入
    尝试插入空元素(如默认构造的对象)时,可以用 set 来确保元素的唯一性。
#include <iostream>
#include <set>int main() {std::set<std::string> mySet;mySet.insert("");  // 插入空字符串mySet.insert("Hello");mySet.insert("");  // 尝试插入重复的空字符串for (const auto& str : mySet) {std::cout << str << std::endl; // 输出空行和 "Hello"}return 0;
}

删除操作

  1. 使用 erase 删除单个元素
    可以使用 erase 函数删除指定的元素。
#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};// 删除元素 3mySet.erase(3);for (const auto& elem : mySet) {std::cout << elem << " ";}// 输出: 1 2 4 5return 0;
}
  1. 使用 erase 删除范围内的元素
    erase 也可以用于删除范围内的元素。
#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5, 6};// 删除元素范围 [3, 5)mySet.erase(mySet.find(3), mySet.find(5));for (const auto& elem : mySet) {std::cout << elem << " ";}// 输出: 1 2 5 6return 0;
}
  1. 删除所有元素
    可以使用 clear 函数清空 set 中的所有元素。
#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};// 清空集合mySet.clear();std::cout << "集合大小: " << mySet.size() << std::endl; // 输出: 0return 0;
}
  1. 使用返回值检查删除结果
    使用 erase 删除元素时,可以通过返回值检查实际删除的元素数量。
#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};// 删除元素 3size_t removedCount = mySet.erase(3);if (removedCount > 0) {std::cout << "成功删除元素 3。" << std::endl;} else {std::cout << "元素 3 不在集合中。" << std::endl;}return 0;
}
  1. 删除自定义对象
    如果 set 中存储的是自定义对象,依然可以使用 erase,前提是重载了 < 运算符。
#include <iostream>
#include <set>struct Person {std::string name;int age;bool operator<(const Person& other) const {return name < other.name; // 按名字排序}
};int main() {std::set<Person> people = {{"Alice", 30}, {"Bob", 25}, {"Charlie", 20}};// 删除 Bobpeople.erase({"Bob", 25});for (const auto& person : people) {std::cout << person.name << " " << person.age << std::endl;}// 输出: Alice 30//       Charlie 20return 0;
}

特别函数操作案例

  1. lower_bound
    功能: 返回一个迭代器,指向容器中第一个大于或等于给定值的元素。如果所有元素都小于该值,则返回 end()。

用法:

iterator lower_bound(const Key& key);

示例

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 4, 5, 6};// 查找大于或等于 4 的第一个元素auto it = mySet.lower_bound(4);if (it != mySet.end()) {std::cout << "lower_bound(4): " << *it << std::endl; // 输出: 4} else {std::cout << "没有找到大于或等于 4 的元素。" << std::endl;}// 查找大于或等于 3 的第一个元素it = mySet.lower_bound(3);if (it != mySet.end()) {std::cout << "lower_bound(3): " << *it << std::endl; // 输出: 4}// 查找大于或等于 7 的第一个元素it = mySet.lower_bound(7);if (it != mySet.end()) {std::cout << "lower_bound(7): " << *it << std::endl; } else {std::cout << "没有找到大于或等于 7 的元素。" << std::endl; // 输出: 没有找到大于或等于 7 的元素。}return 0;
}
  1. upper_bound
    功能: 返回一个迭代器,指向容器中第一个大于给定值的元素。如果所有元素都小于或等于该值,则返回 end()。

用法:

iterator upper_bound(const Key& key);

示例

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 4, 5, 6};// 查找大于 4 的第一个元素auto it = mySet.upper_bound(4);if (it != mySet.end()) {std::cout << "upper_bound(4): " << *it << std::endl; // 输出: 5} else {std::cout << "没有找到大于 4 的元素。" << std::endl;}// 查找大于 2 的第一个元素it = mySet.upper_bound(2);if (it != mySet.end()) {std::cout << "upper_bound(2): " << *it << std::endl; // 输出: 4}// 查找大于 6 的第一个元素it = mySet.upper_bound(6);if (it != mySet.end()) {std::cout << "upper_bound(6): " << *it << std::endl; } else {std::cout << "没有找到大于 6 的元素。" << std::endl; // 输出: 没有找到大于 6 的元素。}return 0;
}

总结
lower_bound: 返回第一个大于或等于给定值的元素。

upper_bound: 返回第一个大于给定值的元素。

查找函数

  1. 查找元素的函数
    在 set 中,主要的查找函数包括 find、count。我们将逐一介绍这些函数的用法及示例。

1,find
find 函数用于查找一个特定的元素。如果找到该元素,返回一个指向该元素的迭代器;如果未找到,返回 end() 迭代器。

用法

iterator find(const Key& key);

示例

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};// 查找元素 3auto it = mySet.find(3);if (it != mySet.end()) {std::cout << "找到了元素: " << *it << std::endl; // 输出: 找到了元素: 3} else {std::cout << "未找到元素。" << std::endl;}// 查找不存在的元素 6it = mySet.find(6);if (it == mySet.end()) {std::cout << "未找到元素 6。" << std::endl; // 输出: 未找到元素 6。}return 0;
}

2, count
count 函数用于统计某个元素在 set 中出现的次数。由于 set 中的元素是唯一的,因此 count 只会返回 0 或 1。

用法

size_type count(const Key& key) const;

示例

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};// 统计元素 3 的出现次数int count = mySet.count(3);std::cout << "元素 3 出现了 " << count << " 次。" << std::endl; // 输出: 元素 3 出现了 1 次。// 统计不存在的元素 6count = mySet.count(6);std::cout << "元素 6 出现了 " << count << " 次。" << std::endl; // 输出: 元素 6 出现了 0 次。return 0;
}

map的定义与使用

在这里插入图片描述

map的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层valu的类型,set默认要求Key⽀持⼩于⽐较,如果不⽀持或者需要的话可以⾃⾏实现仿函数传给第⼆个模版参数,map底层存储数据的内存是从空间配置器申请的。⼀般情况下,我们都不需要传后两个模版参数。map底层是⽤红⿊树实现,增删查改效率是O(logN) ,迭代器遍历是⾛的中序,所以是按key有序顺序遍历的。

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;

pair类型介绍

在 C++ 中,std::pair 是一个用于存储两个相关联数据项的模板类。它定义< utility >头文件中,可以方便地将两个不同类型的值组合在一起。以下是关于 pair 类型的详细介绍。

map底层的红⿊树节点中的数据,使⽤pair<Key,T>存储键值对数据。

typedef pair<const Key, T> value_type;
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
template<class U, class V>
pair (const pair<U,V>& pr): first(pr.first), second(pr.second)
{}
};
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair<T1,T2>(x,y) );
}
  1. 定义和用法
    std::pair 的基本定义如下:
template <class T1, class T2>
struct pair {T1 first;   // 第一个元素T2 second;  // 第二个元素// 构造函数pair();pair(const T1& a, const T2& b);...
};
  1. 构造和初始化
    可以通过不同的方式初始化 std::pair:
#include <iostream>
#include <utility> // 需要包含此头文件int main() {// 使用默认构造函数std::pair<int, double> p1;// 使用参数构造std::pair<int, double> p2(1, 3.14);// 直接初始化std::pair<std::string, int> p3{"apple", 5};// 输出std::cout << "p2: (" << p2.first << ", " << p2.second << ")\n";std::cout << "p3: (" << p3.first << ", " << p3.second << ")\n";return 0;
}
  1. 成员访问
    可以通过 first 和 second 成员访问 pair 中的值:
std::cout << "p2.first: " << p2.first << ", p2.second: " << p2.second << std::endl;
  1. 赋值和比较
    std::pair 支持赋值操作和比较操作:
std::pair<int, double> p4;
p4 = p2; // 赋值if (p2 == p4) {std::cout << "p2 和 p4 相等\n";
}
  1. 应用场景
    返回多个值:可以用 std::pair 返回多个相关的值,例如在函数中返回一个状态码和结果。
std::pair<int, std::string> getData() {return {200, "OK"};
}

键值对:在 std::map 和 std::set 中,std::pair 常被用于存储键值对。

  1. 注意事项
    类型:std::pair 中的两个类型可以相同,也可以不同。
    自定义比较:对于排序或存储在关联容器中,可能需要自定义比较函数。

  2. 例子
    以下是一个使用 std::pair 的完整示例,展示了如何在 C++ 中使用它:

#include <iostream>
#include <utility>
#include <vector>int main() {// 创建一组学生的姓名和分数std::vector<std::pair<std::string, int>> students = {{"Alice", 90},{"Bob", 85},{"Charlie", 95}};// 输出学生信息for (const auto& student : students) {std::cout << student.first << " 的分数是 " << student.second << std::endl;}return 0;
}

map的构造函数与迭代器

map的⽀持正向和反向迭代遍历,遍历默认按key的升序顺序,因为底层是⼆叉搜索树,迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for,map⽀持修改value数据,不⽀持修改key数据,修改关键字数据,破坏了底层搜索树的结构。

// empty (1) ⽆参默认构造
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
map (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());
// copy (3) 拷⻉构造
map (const map& x);
// initializer list (5) initializer 列表构造
map (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

map的增删查

map增接口,插⼊的pair键值对数据,跟set所有不同,但是查和删的接口只⽤关键字key跟set是完全类似的,不过find返回iterator,不仅仅可以确认key在不在,还找到key映射的value,同时通过迭代还可以修改value

Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair<const key_type,mapped_type>
// 单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败
pair<iterator,bool> insert (const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
// 查找k,返回k所在的迭代器,没有找到返回end()
iterator find (const key_type& k);
// 查找k,返回k的个数
size_type count (const key_type& k) const;
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);
// 删除k,k存在返回0,存在返回1
size_type erase (const key_type& k);
// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
// 返回⼤于等k位置的迭代器
iterator lower_bound (const key_type& k);
// 返回⼤于k位置的迭代器
const_iterator lower_bound (const key_type& k) const;

增删查的注意事项

Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair<const key_type,mapped_type>
// 查找k,返回k所在的迭代器,没有找到返回end(),如果找到了通过iterator可以修改key对应的
mapped_type值
iterator find (const key_type& k);
// ⽂档中对insert返回值的说明
// The single element versions (1) return a pair, with its member pair::first
set to an iterator pointing to either the newly inserted element or to the
element with an equivalent key in the map. The pair::second element in the pair
is set to true if a new element was inserted or false if an equivalent key
already existed.
// insert插⼊⼀个pair<key, T>对象
// 1、如果key已经在map中,插⼊失败,则返回⼀个pair<iterator,bool>对象,返回pair对象
first是key所在结点的迭代器,second是false
// 2、如果key不在在map中,插⼊成功,则返回⼀个pair<iterator,bool>对象,返回pair对象
first是新插⼊key所在结点的迭代器,second是true
// 也就是说⽆论插⼊成功还是失败,返回pair<iterator,bool>对象的first都会指向key所在的迭
代器
// 那么也就意味着insert插⼊失败时充当了查找的功能,正是因为这⼀点,insert可以⽤来实现
operator[]
// 需要注意的是这⾥有两个pair,不要混淆了,⼀个是map底层红⿊树节点中存的pair<key, T>,另
⼀个是insert返回值pair<iterator,bool>
pair<iterator,bool> insert (const value_type& val);
mapped_type& operator[] (const key_type& k);
// operator的内部实现
mapped_type& operator[] (const key_type& k)
{
// 1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储
mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊+修改功能
// 2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的
迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能
pair<iterator, bool> ret = insert({ k, mapped_type() });
iterator it = ret.first;
return it->second;
}

插入函数

  1. 定义和包含头文件
    首先,确保包含 头文件:
#include <map>
  1. 插入元素的方法
    2.1 使用 insert()
    insert() 方法可以插入单个元素或多个元素。

插入单个元素

std::map<int, std::string> myMap;
myMap.insert(std::make_pair(1, "Apple")); // 使用 make_pair
myMap.insert({2, "Banana"}); // 使用初始化列表

插入多个元素

std::map<int, std::string> myMap;
myMap.insert({{1, "Apple"}, {2, "Banana"}, {3, "Cherry"}});

2.2 使用 emplace()
emplace() 方法更高效,因为它可以直接在 map 中构造元素:

myMap.emplace(4, "Date"); // 直接插入

2.3 使用下标运算符 []
下标运算符也可以插入元素,若键不存在,会自动创建一个新元素:

myMap[5] = "Elderberry"; // 若 5 不存在,则插入
  1. 返回值
    insert() 返回一个 pair,其中 first 是插入的位置的迭代器,second 是一个布尔值,表示插入是否成功(如果键已存在则为 false)。
auto result = myMap.insert({1, "Apple"});
if (!result.second) {std::cout << "Key already exists.\n";
}

emplace() 和下标运算符同样具有类似的返回值特性。
4. 注意事项
唯一性:map 中的键是唯一的,插入相同的键会导致覆盖旧值。
有序性:map 会根据键的顺序自动排序。
性能:emplace() 通常比 insert() 更高效,特别是在插入复杂对象时。

  1. 示例代码
    以下是一个完整示例,展示 map 的插入操作:
#include <iostream>
#include <map>int main() {std::map<int, std::string> myMap;// 使用 insert()myMap.insert(std::make_pair(1, "Apple"));myMap.insert({2, "Banana"});// 使用 emplace()myMap.emplace(3, "Cherry");// 使用下标运算符myMap[4] = "Date";// 输出所有元素for (const auto& pair : myMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

删除函数
std::map 提供了多种删除元素的方法。以下是有关删除函数的详细说明:

  1. 使用 erase()
    erase() 是最常用的删除函数,可以通过键或迭代器删除元素。

1.1 根据键删除
可以使用键直接删除元素:

std::map<int, std::string> myMap;
// 假设 myMap 中已有元素
myMap.erase(1); // 删除键为 1 的元素

1.2 根据迭代器删除
可以通过迭代器删除特定位置的元素:

auto it = myMap.find(2);
if (it != myMap.end()) {myMap.erase(it); // 删除键为 2 的元素
}

1.3 删除一段元素
可以使用两个迭代器删除范围内的元素:

myMap.erase(myMap.find(1), myMap.find(4)); // 删除键在 1 到 4 之间的元素(不包括 4)
  1. 返回值
    erase() 返回值:根据删除方式不同,返回值如下:
    根据键删除时,返回删除的元素数量(成功删除返回 1,未找到返回 0)。
    根据迭代器删除时,返回被删除元素之后的迭代器。
  2. 注意事项
    键的存在性:在删除前可以使用 find() 检查键是否存在,以避免不必要的删除操作。
    迭代器失效:删除操作会使得指向被删除元素的迭代器失效,因此在使用迭代器删除后,应该更新迭代器。
    不会抛出异常:在删除操作中,erase() 不会因为元素不存在而抛出异常。
  3. 示例代码
    以下是一个完整的示例,展示如何使用 erase() 删除 map 中的元素:
#include <iostream>
#include <map>int main() {std::map<int, std::string> myMap = {{1, "Apple"},{2, "Banana"},{3, "Cherry"},{4, "Date"}};// 删除键为 2 的元素myMap.erase(2);// 使用迭代器删除键为 3 的元素auto it = myMap.find(3);if (it != myMap.end()) {myMap.erase(it);}// 输出剩余元素for (const auto& pair : myMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

查找函数

  1. 使用 find()
    find() 函数用于查找 map 中是否存在指定的键。

示例用法

#include <iostream>
#include <map>int main() {std::map<int, std::string> myMap = {{1, "Apple"},{2, "Banana"},{3, "Cherry"},{4, "Date"}};int keyToFind = 2;auto it = myMap.find(keyToFind);if (it != myMap.end()) {std::cout << "Found: " << it->first << " => " << it->second << std::endl;} else {std::cout << "Key " << keyToFind << " not found." << std::endl;}return 0;
}
  1. 使用 count()
    count() 函数返回指定键的元素数量。由于 std::map 中的键是唯一的,因此返回值要么是 0(键不存在),要么是 1(键存在)。

示例用法

int count = myMap.count(keyToFind);
if (count > 0) {std::cout << "Key " << keyToFind << " exists." << std::endl;
} else {std::cout << "Key " << keyToFind << " does not exist." << std::endl;
}
  1. 使用下标运算符 []
    虽然下标运算符不仅用于查找,还可用于插入和访问元素,但在查找时也可以使用。若键不存在,则会插入一个默认值。

示例用法

std::string value = myMap[keyToFind]; // 如果 keyToFind 不存在,则插入默认值
std::cout << "Value: " << value << std::endl;

注意:如果使用 [] 运算符查找一个不存在的键,map 会自动插入该键,并用其类型的默认值初始化。

  1. 使用 lower_bound() 和 upper_bound()
    这两个函数用于获取指向特定键的迭代器,可以用于范围查找。

lower_bound() 返回第一个不小于给定键的元素的迭代器。
upper_bound() 返回第一个大于给定键的元素的迭代器。
示例用法

auto lb = myMap.lower_bound(3);
if (lb != myMap.end()) {std::cout << "Lower bound of 3: " << lb->first << " => " << lb->second << std::endl;
}auto ub = myMap.upper_bound(3);
if (ub != myMap.end()) {std::cout << "Upper bound of 3: " << ub->first << " => " << ub->second << std::endl;
}

总结
find(): 返回指向指定键的迭代器,如果键不存在则返回 end()。

count(): 返回指定键的个数(0或1)。

下标运算符 []: 访问或插入元素,若键不存在则插入默认值。

lower_bound() 和 upper_bound(): 用于范围查找,返回迭代器。


http://www.mrgr.cn/news/36334.html

相关文章:

  • 单链表的实现(C语言)
  • ③无需编程 独立通道 Modbus主站EtherNet/IP转ModbusRTU/ASCII工业EIP网关串口服务器
  • 深入探秘 WorkManager:Android 异步任务管理的强大工具
  • Solidity智能合约中的异常处理(error、require 和 assert)
  • 回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测
  • vue项目报错: At least one is required in a single file component.的主要原因及解决办法
  • linux服务器安装原生的php环境
  • Adaptive Object Detection with Dual Multi-Label Prediction
  • JS面试真题 part6
  • Structure-Aware Transformer for Graph Representation Learning
  • 量化交易四大邪术之三:春去花还在
  • 《动手学深度学习》笔记2.2——神经网络从基础→进阶 (参数管理-每层的权重/偏置)
  • docker中搭建nacos并将springboot项目的配置文件转移到nacos中
  • Proto3 深度解读:Protobuf 的用法与实例分析(C++)
  • Springboot jPA+thymeleaf实现增删改查
  • 第二十八篇——用间篇:使用间谍,先学习花钱的价值观
  • Volume数据管理
  • 前缀和(3)_寻找数组的中心下标
  • 【Java】注解与单元测试的使用【主线学习笔记】
  • 给自己的笔记本加一个公网IP