地图在 C++ 标准模板库 (STL)

⚡ 智能摘要

地图在 C++ 是标准模板库中的一个关联容器,它将元素存储为排序的键值对,其中每个唯一的键映射到一个值,并支持快速查找、插入和有序遍历。

  • 🗺️ 关联容器: A C++ map 将项目存储为键值对,键是唯一的,并且会自动排序。
  • 🧩 头部和语法: 包含映射头文件,然后声明 std::map用于存储类型对的名称。
  • 🛠️ 内置功能: begin()、size()、empty()、insert()、find()、erase() 和 clear() 管理地图内容。
  • 🔄 迭代: 双向迭代器按排序键的顺序遍历映射元素,以进行读取或删除操作。
  • ???? 唯一密钥: 两个元素不能共享一个键,这使得映射成为关联数组的理想选择。
  • 🤖 人工智能辅助: GitHub Copilot 和类似的 AI 助手可以根据简短的评论生成映射声明和循环。

地图在 C++ STL

Map 是什么 C++?

In C++映射(Map)是一种关联容器,以映射的形式存储数据项。映射中的每个数据项都由一个键值对和一个映射值组成。两个映射值不能具有相同的键值对。

键值用于对元素进行排序和唯一标识,而映射值则存储与每个键关联的内容。两者类型可能不同,但成员类型会将它们组合成一个包含两者的键值对。

在编写任何代码之前,了解为什么地图通常是合适的容器会很有帮助。

为什么要使用 std::map?

以下是使用地图的理由:

  • std::map 只存储唯一键,并根据选定的排序标准进行排序。
  • 使用密钥搜索元素既简单又快捷。
  • 每个键仅附加一个元素。
  • std::map 可以用作关联数组。
  • std::map 可以使用平衡二叉树实现。

要利用这些优势,首先要了解声明语法。

句法

要声明 std::map,请使用以下语法:

std::map<key_datatype, value_datatype>map_name; 
  • 键数据类型 表示地图键的数据类型。
  • 值数据类型 表示与映射键对应的值的数据类型。
  • 地图名称 是地图的名称。

例如:

map<string, int> my_map; 

我们声明了一个名为 my_map 的映射。该映射的键数据类型为字符串,值数据类型为整数。

会员类型

成员函数可以使用以下成员类型作为参数或返回类型:

  • 密钥类型: 键(模板中的第一个参数)
  • 映射类型: T(模板中的第二个参数)
  • 键比较: 比较(模板中的第三个参数)
  • 分配器类型: 分配(模板中的第四个参数)
  • 值类型: 一对
  • 值比较: 用于比较元素的嵌套函数类
  • 参考: 分配器类型::reference
  • const_reference: 分配器类型::const_reference
  • 指针: 分配器类型::指针
  • const_pointer(常量指针): 分配器类型::const_pointer
  • 迭代器(iterator): 指向 value_type 的双向迭代器
  • const_iterator(常量迭代器): 指向 const value_type 的双向迭代器
  • 反向迭代器(reverse_iterator): 反向迭代器
  • const_reverse_iterator(反向迭代器): 常数反向迭代器
  • 差异类型: ptrdiff_t
  • 尺码类型: 尺寸_t

std::map 的内置函数

std::map 带有内置函数。其中包括:

  • 开始 () – 此函数返回指向映射中第一个元素的迭代器。
  • 尺寸() – 此函数返回映射中的项目数。
  • 空的() – 此函数返回一个布尔值,表示映射是否为空。
  • 插入(键值对) – 此函数将一个新的键值对插入到映射中。
  • 查找(val) – 如果找到 val 元素,此函数会将迭代器返回给该元素。否则,它返回 m.end()。
  • 擦除(迭代器位置) – 此函数删除迭代器指向的位置处的项。
  • 擦除(const g) – 此函数从映射中删除键值对 g。
  • 明确() 此函数会删除地图中的所有项目。

定义好函数之后​​,以下示例将把它们付诸实践,首先是迭代。

迭代 Map 元素

您可以遍历地图元素。我们只需要创建一个迭代器并使用它即可。例如:

例子1

#include <iostream>
#include <string>
#include <map> 

using namespace std;
int main() {

	map<int, string> Students;

	Students.insert(std::pair<int, string>(200, "Alice"));

	Students.insert(std::pair<int, string>(201, "John"));

	cout << "Map size is: " << Students.size() << endl;

	cout << endl << "Default map Order is: " << endl;

	for (map<int, string>::iterator it = Students.begin(); it != Students.end(); ++it) {

		cout << (*it).first << ": " << (*it).second << endl;
	}
}

输出:

C++ 映射迭代示例 1 输出

以下是代码截图:

C++ 地图迭代示例 1 代码

Code 说明:

  1. 将 iostream 头文件包含到我们的代码中以使用其功能。
  2. 将字符串头文件包含到我们的代码中以使用其功能。
  3. 将地图头文件包含到我们的代码中以使用其功能。
  4. 将 std 命名空间包含到我们的代码中以便使用它的类而无需调用它。
  5. 调用 main() 函数。{ 标记函数主体的开始。
  6. 创建一个名为 Students 的映射,其中键是整数,值是字符串。
  7. 将值插入到映射 Students 中。键 200 和值 Alice 将被插入到映射中。
  8. 将值插入到映射 Students 中。键 201 和值 John 将被插入到映射中。
  9. 使用 size() 函数获取名为 Students 的地图的大小。这应该返回 2。
  10. 在控制台上打印一些文本。
  11. 使用 for 循环创建一个名为 it 的迭代器,以迭代名为 Students 的映射的元素。
  12. 在控制台上打印地图学生的值。
  13. for 循环主体的结束。
  14. main() 函数体结束。

在 std::map 中插入数据

您可以使用 insert() 函数向 std::map 中添加元素。请记住,std::map 的键必须是唯一的。

因此,它首先检查每个键是否存在于映射中。如果存在,则不会插入该条目,而是返回现有条目的迭代器。如果不存在,则插入该条目。

该函数有以下几种变体:

  • 插入(对) – 通过这种变体,将键值对插入到映射中。
  • 插入(start_itr, end_itr) – 通过这种变化,条目将插入到另一个映射中由 start_itr 和 end_itr 定义的范围内。

insert_or_assign() 函数的工作方式与 insert() 函数相同,但如果给定的键已存在于映射中,则会修改其值。

例子2

#include <map>
#include <iostream>

using namespace std;

int main() {

	map<int, int> m{ {1,3} , {2,4} , {3,5} };

	m.insert({ 5, 6 });
	m.insert({ 1, 8 });

	m.insert_or_assign(1, 6);  
	
	cout << "Key\tElement\n";
	for (auto itr = m.begin(); itr != m.end(); ++itr) {
		cout << itr->first << '\t' << itr->second << '\n';
	}
	return 0;
}

输出:

C++ 映射插入示例 2 输出

以下是代码截图:

C++ 地图插入示例 2 代码

Code 说明:

  1. 将地图头文件包含到我们的代码中以使用其功能。
  2. 将 iostream 头文件包含到我们的代码中以使用其功能。
  3. 将 std 命名空间包含到我们的代码中以便使用它的类而无需调用它。
  4. 调用 main() 函数。{ 标记函数主体的开始。
  5. 创建一个名为 m 的映射,其中键为整数,值也为整数。映射中已包含三个条目。
  6. 在映射 m 中插入一个新条目。键 5 和值 6 将被插入到映射中。
  7. 尝试对已存在的键进行输入。由于键 1 已存在于映射中,因此不会进行输入。
  8. 使用 insert_or_assign() 函数插入或修改现有条目。由于键 1 已存在,其值将被更改为 6。
  9. 在控制台上打印一些文本。“\t”字符创建一个水平空格,而“\n”字符将鼠标光标移动到下一行。
  10. 使用 for循环 创建一个名为 itr 的迭代器来迭代名为 m 的映射中的元素。
  11. 在控制台上打印映射 m 的值。“\t”字符在每个键和其对应的值之间创建一个水平空格。相反,“\n”字符在每次迭代后将鼠标光标移动到下一行。
  12. for 循环主体的结束。
  13. 程序成功完成后必须返回一个值。
  14. main() 函数体结束。

在地图中搜索

我们可以使用 `find()` 函数按键在映射中查找元素。如果找不到指定的键,该函数返回 `std::map::end`。否则,将返回找到的元素的迭代器。

例子3

#include <iostream>
#include <string>
#include <map> 
using namespace std;
int main() {
	map<int, string> Students;
	Students.insert(std::pair<int, string>(200, "Alice"));
	Students.insert(std::pair<int, string>(201, "John"));
	std::map<int, string>::iterator it = Students.find(201);
	if (it != Students.end()) {
		std::cout << endl << "Key 201 has the value: => "<< Students.find(201)->second << '\n';
	}
}

输出:

C++ 地图查找搜索示例 3 输出

以下是代码截图:

C++ 地图查找搜索示例 3 代码

Code 说明:

  1. 将 iostream 头文件包含到我们的代码中以使用其功能而不会出现错误。
  2. 将字符串头文件包含到我们的代码中以便使用其功能而不会出现错误。
  3. 将地图头文件包含到我们的代码中以便使用其功能而不会出现错误。
  4. 将 std 命名空间包含到我们的代码中以便使用它的类而无需调用它。
  5. 调用 main() 函数。{ 标记 main() 函数体的开始。
  6. 创建一个名为 Students 的映射,其键为整数,值为字符串。
  7. 将值插入到映射 Students 中。键 200 和值 Alice 将被插入到映射中。
  8. 将值插入到映射 Students 中。键 201 和值 John 将被插入到映射中。
  9. 查找与键 201 关联的值。
  10. 使用 if 语句检查是否找到该键的值。
  11. 在控制台上打印密钥的值以及一些文本。
  12. if 语句主体结束。
  13. main() 函数体结束。

从地图中删除数据

我们可以使用 `erase()` 函数从映射中删除一个值。我们只需创建一个指向要删除元素的迭代器,然后将该迭代器传递给 `erase()` 函数即可。

例子4

#include <iostream>
#include <string>
#include <map>

using namespace std;
int main() {

	map<std::string, int> my_map;

	my_map.insert(std::make_pair("cow", 1));

	my_map.insert(std::make_pair("cat", 2));

	my_map["lion"] = 3;

	map<std::string, int>::iterator it = my_map.find("cat");

	my_map.erase(it);

	for (map<string, int>::iterator it = my_map.begin(); it != my_map.end(); ++it)

		cout << (*it).first << ": " << (*it).second << endl;

  return 0;
}

输出:

C++ 映射擦除删除示例 4 输出

以下是代码截图:

C++ 地图擦除删除示例 4 代码

Code 说明:

  1. 将 iostream 头文件包含到我们的代码中以使用其功能。
  2. 将字符串头文件包含到我们的代码中以使用其功能。
  3. 将地图头文件包含到我们的代码中以使用其功能。
  4. 将 std 命名空间包含到我们的代码中以便使用它的类而无需调用它。
  5. 调用 main() 函数。{ 标记 main() 函数体的开始。
  6. 创建一个名为 my_map 的映射,其键为字符串,值为整数。
  7. 将值插入到映射 my_map 中。键为 Cow,值 1 将插入到映射中。
  8. 将值插入到映射 my_map 中。键为 Cat,值 2 将插入到映射中。
  9. 将值 3 添加到映射 my_map 中,并以狮子为键。
  10. 创建一个迭代器来迭代映射 my_map 以寻找键 cat。
  11. 删除迭代器指向的元素。
  12. 使用迭代器从头到尾遍历映射 my_map 的元素。
  13. 在控制台上打印出地图my_map的内容。
  14. 程序成功完成后必须返回输出。
  15. main() 函数体结束。

常见问题

std::map 使用自平衡二叉搜索树对键进行排序,操作时间复杂度为 O(log n)。std::unordered_map 使用哈希表,平均查找时间复杂度为 O(1),但键的存储顺序不固定。根据您的排序需求进行选择。

std::map 通常实现为自平衡二叉搜索树,最常见的是红黑树。这样可以保持键的有序性,并保证插入、删除和搜索操作的时间复杂度为对数级。

不。`std::map` 只存储唯一键,因此插入已存在的键不会覆盖它。如果需要重复键,请使用 `std::multimap`,它允许多个元素共享同一个键值。

使用 `map_name[key]` 读取或赋值;下标运算符会在键缺失时插入一个默认值。`at()` 成员会在键缺失时抛出异常,因此使用 `at()` 更安全。

将自定义比较器(例如 std::map)作为第三个模板参数传递。 >. 更高级的比较器会按照从高到低的顺序排列键,而不是默认的升序排列。

`std::map` 存储键值对,并按键查找值,而 `std::set` 只存储唯一键,不存储任何关联值。两者都保持元素有序,但 `map` 会将数据与每个键关联起来。

是的。AI 代码助手可以将简短的提示或注释转换为可运行的 std::map 代码,包括声明、插入调用和迭代器循环。编译前务必检查生成的键类型、顺序和边界情况。

是的。 GitHub 副驾驶 它会在你输入时提示映射声明、插入和查找调用以及迭代循环。它能很好地处理重复的样板代码,但你仍然应该在构建之前验证键的唯一性和逻辑。

总结一下这篇文章: