【C++ STL】map容器的基本使用

0 阅读4分钟

map容器

map 是 C++ STL 中最常用的有序关联式容器,核心是存储 key-value(键值对),且 key 唯一、自动排序,底层基于红黑树实现,保证增删查改的时间复杂度稳定在O(logn)。 特性:

  • 存储结构:键值对(key-value),每个 key 对应唯一 value
  • 排序规则:默认按 key 升序排列(可自定义排序规则)
  • 可修改性:key 不可修改(需删除后重新插入),value 可直接修改
  • 底层实现:红黑树(平衡二叉树),避免退化成链表,保证高效操作
  • 空值处理:用 [] 访问不存在的 key 时,会自动插入该 keyvalue 为默认值

基本使用

  • 使用 map 必须包含头文件
#include <map> // 核心头文件
  • 初始化
// 1、空map(默认构造函数
// 键(int)值(string)
map<int, string> m1;
// key(可以是自定义类型)
map<pair<int, int>, vector<int>> m2;

// 2、列表初始化(c++ 11)
map<int, string> m3 = {
	{1, "zs"},
	{2, "ls"}
};

// 3、拷贝构造
map<int, string> m4(m3);

// 4、范围初始化
map<int, string> m5(m3.begin(), m3.end());

// 5、自定义键的排序规则
// 这里的排序规则只针对键,可以传入比较函数或者仿函数
map<int, string, greater<int>> m6;

核心操作API

插入元素

  • []运算符,m[key] = value的方式,比较简单(key 不存在则插入,存在则修改 value);
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

// []插入元素
m[3] = "ww";

cout << m[3] << endl;
  • insert({key, value}),key 存在则插入失败(不修改),返回 pair <迭代器,bool>
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

// insert插入元素
pair<map<int,string>::iterator, bool> ret = m.insert({ 3, "ww" });

cout << ret.second << endl;		// 1

ret = m.insert({ 3, "zl" });
cout << ret.second << endl;		// 0
  • emplace(key, value)原地构造,避免拷贝,性能优于 insert,key 存在则插入失败
  • insert_or_assign(key, value)C++17 新增,key 存在则修改 value,不存在则插入(兼顾 [] 和 insert 的优点)
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

// insert_or_assign插入元素
m.insert_or_assign(3, "ww");

m.insert_or_assign(3, "ll");
cout << m[3] << endl;		// ll

访问元素

  • [] 运算符,不建议使用(不存在则会插入默认值)
  • at(),不存在则抛出异常
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

cout << m.at(2) << endl;
  • 迭代器访问
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

auto ret = m.find(1);
// 这里必须判断是否找到元素
if (ret != m.end())
{
	cout << ret->first << ":" << ret->second << endl;
}

查找元素

  • find,返回迭代器,如果未找到返回m.end()
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

auto ret = m.find(1);
// 这里必须判断是否找到元素
if (ret != m.end())
{
	cout << ret->first << ":" << ret->second << endl;
}
  • count(),仅判断是否存在

删除元素

  • 按key删除,返回删除元素的个数
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

int ret = m.erase(1);
cout << ret << endl;		// 1
  • 按迭代器删除
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

auto ret = m.find(1);
// 这里必须判断是否找到元素
if (ret != m.end())
{
	// 返回的是迭代器
	auto re = m.erase(ret);
	cout << re->second << endl;
}
  • 删除范围,左开右闭
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

m.erase(m.begin(), m.find(2));
  • clear清空所有元素

遍历元素

  • 普通迭代器,可读写
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

for (map<int, string>::iterator it = m.begin(); it!= m.end(); ++it)
{
	cout << "key = " << it->first << ", value = " << it->second << endl;
}
  • const迭代器,只读
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

for (map<int, string>::const_iterator it = m.cbegin(); it!= m.cend(); ++it)
{
	cout << "key = " << it->first << ", value = " << it->second << endl;
}
  • 范围for循环(c++11)
map<int, string> m = {
	{1, "zs"},
	{2, "ls"}
};

for (auto& p : m)
{
	cout << p.first << ": " << p.second << endl;
}
  • 反向迭代器

进阶用法

  • 自定义排序规则
    • 按key降序
map<int, string, greater<int>> m6;
- 自定义排序函数
// 按照字符串长度排序(倒序)
struct strLenCmp {
	bool operator()(const string& a, const string& b) const
	{
		return a.size() > b.size();
	}
};

int main()
{
	map<string, string, strLenCmp> m = {
		{"aaa", "a"},
		{"bbbb", "b"},
		{"ccccc", "c"}
	};

	for (auto& p : m) {
		cout << p.first << endl;
	}

	return EXIT_SUCCESS;
};
-`key` 是自定义结构体 / 类,必须重载 `<` 运算符(满足排序规则)
  • 性能优化
    • 避免频繁使用 [] 访问不存在的 key(会自动插入默认值,浪费内存);
    • 插入大量元素时,优先用 emplace() 而非 insert()(原地构造,减少拷贝);
    • 遍历只读场景用 const 迭代器(避免误修改,且性能略优);
    • 若无需有序,优先用 unordered_map(哈希表,平均查找 O(1))。

结束语

  • map 核心是有序唯一键值对,底层红黑树保证 O(logn) 操作效率,默认按 key 升序排列;
  • 插入优先用 emplace()(高性能),访问优先用 find()+ 迭代器(避免 [] 自动插入空值),删除用 erase(key)(最直观);
  • 自定义 key 需重载 < 运算符,自定义排序需传入仿函数,只读遍历用 const 迭代器更安全。