C++ 中 std::map 是一个非常有用的关联容器,它提供了一种键值对(key-value)的存储方式,并且会根据键(key)自动进行排序。

1. 头文件与声明

首先,你需要包含 <map> 头文件。

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

using namespace std;

int main() {
    // 声明一个 map,key 为 string 类型,value 为 int 类型
    map<string, int> myMap;
    
    // 其他操作...
    return 0;
}

2. 插入元素 (Insert)

有几种常见的方法可以向 map 中插入元素:

方法一:使用 insert() 函数和 make_pair

myMap.insert(make_pair("Apple", 10));

方法二:使用 insert() 函数和花括号 {} (C++11及以上)

myMap.insert({"Banana", 20});

方法三:使用 emplace() 函数 (C++11及以上,更高效)
emplace 会直接在容器内部构造元素,避免了临时对象的创建和拷贝。

myMap.emplace("Orange", 30);

方法四:使用 [] 操作符 (最常用、最直观)
如果键不存在,[] 操作符会先创建一个带有该键的新元素,并将其值初始化为默认值(对于 int 是 0),然后返回这个值的引用让你来赋值。

myMap["Mango"] = 40; // 直接像数组一样赋值

重要区别

  • insert/emplace:如果键已存在,不会覆盖原有的值,插入操作会失败。

  • []操作符:如果键已存在,覆盖原有的值。

3. 访问元素 (Access)

方法一:使用 [] 操作符

cout << "Apple: " << myMap["Apple"] << endl; // 输出 10

注意:如果键 "Apple" 不存在,myMap["Apple"] 会自动创建一个键为 "Apple",值为 0 的元素。这有时不是你想要的行为。

方法二:使用 at() 函数 (更安全)

cout << "Banana: " << myMap.at("Banana") << endl; // 输出 20

注意:如果键 "Banana" 不存在,at() 会抛出一个 std::out_of_range 异常。

方法三:使用迭代器 (Iterator) 遍历访问

// 使用迭代器遍历 map (按键的升序排列)
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
    // it->first 是 key, it->second 是 value
    cout << it->first << ": " << it->second << endl;
}

// C++11 起支持的更简洁的范围基于 for 循环
for (const auto &pair : myMap) {
    cout << pair.first << ": " << pair.second << endl;
}

4. 查找元素 (Find)

使用 find() 函数来检查一个键是否存在。这是最推荐的方法,因为它不会意外创建新元素。

// 查找键 "Cherry"
auto it = myMap.find("Cherry");

// 判断是否找到
if (it != myMap.end()) {
    cout << "Found Cherry: " << it->second << endl;
} else {
    cout << "Cherry not found." << endl;
}

find() 返回一个指向该元素的迭代器,如果没找到,则返回 myMap.end()

5. 删除元素 (Erase)

方法一:通过迭代器删除

// 先找到要删除的元素
auto it = myMap.find("Apple");
if (it != myMap.end()) {
    myMap.erase(it); // 通过迭代器删除
}

方法二:通过键直接删除

// 直接通过键删除,返回删除的元素个数 (对于 map,只能是 0 或 1)
size_t numErased = myMap.erase("Banana");
cout << "Erased " << numErased << " elements." << endl;

方法三:删除一个范围内的元素 (不常用)

// 删除从 begin() 开始的两个元素
myMap.erase(myMap.begin(), next(myMap.begin(), 2));

6. 其他常用操作

检查是否为空

if (myMap.empty()) {
    cout << "Map is empty." << endl;
}

获取元素个数

cout << "Map size: " << myMap.size() << endl;

清空 map

myMap.clear();

综合示例

下面是一个将所有操作整合在一起的完整示例:

#include <iostream>
#include <map>
#include <string>
using namespace std;

int main() {
    // 1. 声明 & 插入
    map<string, int> fruitBasket;
    fruitBasket.insert({"Apple", 5});
    fruitBasket.emplace("Banana", 3);
    fruitBasket["Orange"] = 8;
    fruitBasket["Mango"] = 6; // 使用 [] 插入

    // 尝试插入一个已存在的键 (不会生效)
    fruitBasket.insert({"Apple", 100}); // Apple 的值仍然是 5

    // 2. 访问 & 遍历
    cout << "Fruit basket contents:" << endl;
    for (const auto &pair : fruitBasket) {
        cout << "  " << pair.first << ": " << pair.second << endl;
    }

    // 3. 查找
    string searchKey = "Mango";
    auto it = fruitBasket.find(searchKey);
    if (it != fruitBasket.end()) {
        cout << "\nFound " << searchKey << ", quantity: " << it->second << endl;
    } else {
        cout << "\n" << searchKey << " not found." << endl;
    }

    // 4. 修改 (通过 find 检查后使用 [] 修改)
    fruitBasket["Apple"] = 10; // 修改 Apple 的数量
    cout << "\nApple quantity updated to: " << fruitBasket["Apple"] << endl;

    // 5. 删除
    fruitBasket.erase("Banana");
    cout << "\nAfter erasing Banana, size: " << fruitBasket.size() << endl;

    // 6. 安全访问示范
    try {
        cout << "Trying to access a non-existing key with at()..." << endl;
        cout << fruitBasket.at("DragonFruit") << endl;
    } catch (const out_of_range &e) {
        cout << "Error: " << e.what() << " (Key not found)" << endl;
    }

    // 使用 find 安全访问
    it = fruitBasket.find("DragonFruit");
    if (it != fruitBasket.end()) {
        cout << "DragonFruit: " << it->second << endl;
    } else {
        cout << "Safely determined DragonFruit is not in the basket." << endl;
    }

    return 0;
}

关键特点总结:

  1. 有序性std::map 中的元素总是按照键(key)的升序进行排序。

  2. 唯一性:每个键只能在 map 中出现一次。

  3. 底层实现:通常基于红黑树(一种平衡二叉搜索树)实现,因此插入、删除、查找操作的时间复杂度均为 O(log n)

  4. 替代品:如果你不需要排序,但需要更快的访问速度(平均 O(1)),可以考虑 std::unordered_map(基于哈希表)。

deepseek辅助创作

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐