C++中的map容器详解

C++中的map容器详解

1. map概述

map是C++ STL中的关联容器,它存储**键值对(key-value)**并按key自动排序。map基于红黑树实现,提供高效的查找、插入和删除操作。

2. 基本特性

  • 唯一键值:每个key只能出现一次
  • 自动排序:元素总是按key排序
  • 高效查找 :基于key的查找时间复杂度为O(log⁡2n)O(\log_2 n)O(log2n)
  • 键不可修改 :key是const的,value可以修改

3. 头文件与声明

cpp 复制代码
#include <map>
using namespace std;

map<int, string> m1;                     // 空map,key为int,value为string
map<string, int, greater<string>> m2;    // 空map,按key降序排列
map<string, int> m3 = {{"Alice", 25}, {"Bob", 30}};  // 初始化列表

4. 构造函数与初始化

4.1 默认构造

cpp 复制代码
map<string, double> m;  // 创建空map

4.2 范围构造

cpp 复制代码
pair<string, int> arr[] = {{"A", 1}, {"B", 2}};
map<string, int> m(arr, arr+2);  // 用数组范围构造

4.3 拷贝构造

cpp 复制代码
map<string, int> m2(m1);  // 拷贝构造

5. 容量操作

5.1 size()

cpp 复制代码
cout << m.size();  // 返回元素数量

5.2 empty()

cpp 复制代码
if(m.empty()) {
    cout << "Map is empty";
}

5.3 max_size()

cpp 复制代码
cout << m.max_size();  // 返回map可容纳的最大元素数

6. 元素访问

6.1 operator[]

cpp 复制代码
m["Alice"] = 25;      // 插入或修改元素
int age = m["Bob"];   // 访问元素(如果不存在会插入默认值)

6.2 at()

cpp 复制代码
int age = m.at("Alice");  // 访问元素(如果不存在抛出out_of_range异常)

7. 修改操作

7.1 insert()

cpp 复制代码
m.insert({"Charlie", 28});               // 插入单个元素
m.insert(make_pair("David", 32));        // 使用make_pair
m.insert({{"Eve", 27}, {"Frank", 40}});  // 插入多个元素

7.2 emplace()

cpp 复制代码
m.emplace("Grace", 35);  // 原地构造元素,比insert更高效

7.3 erase()

cpp 复制代码
m.erase("Alice");                   // 删除指定key的元素
m.erase(m.begin());                 // 删除迭代器指向的元素
m.erase(m.begin(), m.find("Bob"));  // 删除范围元素

7.4 clear()

cpp 复制代码
m.clear();  // 清空所有元素

7.5 swap()

cpp 复制代码
map<string, int> m2;
m.swap(m2);  // 交换两个map的内容

8. 查找操作

8.1 find()

cpp 复制代码
auto it = m.find("Alice");  // 查找元素,返回迭代器
if(it != m.end()) {
    cout << "Found: " << it->first << " => " << it->second;
}

8.2 count()

cpp 复制代码
if(m.count("Bob")) {  // 返回匹配key的数量(0或1)
    cout << "Key exists";
}

8.3 lower_bound() & upper_bound()

cpp 复制代码
auto lb = m.lower_bound("B");  // 返回第一个不小于"B"的元素的迭代器
auto ub = m.upper_bound("D");  // 返回第一个大于"D"的元素的迭代器

8.4 equal_range()

cpp 复制代码
auto range = m.equal_range("C");  // 返回等于"C"的元素范围
// range.first是lower_bound, range.second是upper_bound

9. 迭代器

9.1 begin() & end()

cpp 复制代码
for(auto it = m.begin(); it != m.end(); ++it) {
    cout << it->first << ": " << it->second << endl;
}

9.2 rbegin() & rend()

cpp 复制代码
for(auto rit = m.rbegin(); rit != m.rend(); ++rit) {
    cout << rit->first << ": " << rit->second << endl;  // 反向遍历
}

10. 完整示例

cpp 复制代码
#include <iostream>
#include <map>
#include <string>
using namespace std;

int main() {
    // 创建并初始化map
    map<string, int> ageMap = {{"Alice", 25}, {"Bob", 30}};
    
    // 插入元素
    ageMap.insert({"Charlie", 28});
    ageMap.emplace("David", 32);
    ageMap["Eve"] = 27;  // 使用operator[]插入
    
    // 修改元素
    ageMap["Alice"] = 26;  // 修改Alice的年龄
    
    // 查找元素
    if(ageMap.find("Bob") != ageMap.end()) {
        cout << "Bob's age: " << ageMap["Bob"] << endl;
    }
    
    // 删除元素
    ageMap.erase("Charlie");
    
    // 遍历map
    cout << "All entries:" << endl;
    for(const auto& [name, age] : ageMap) {  // C++17结构化绑定
        cout << name << ": " << age << endl;
    }
    
    // 范围查询
    cout << "Names between A and C:" << endl;
    auto low = ageMap.lower_bound("A");
    auto up = ageMap.upper_bound("C");
    for(auto it = low; it != up; ++it) {
        cout << it->first << ": " << it->second << endl;
    }
    
    // 容量信息
    cout << "Size: " << ageMap.size() << endl;
    cout << "Is empty: " << (ageMap.empty() ? "Yes" : "No") << endl;
    
    return 0;
}

11. 自定义比较函数

cpp 复制代码
struct CaseInsensitiveCompare {
    bool operator()(const string& a, const string& b) const {
        return strcasecmp(a.c_str(), b.c_str()) < 0;
    }
};

map<string, int, CaseInsensitiveCompare> caseInsensitiveMap;

12. 性能提示

  1. 查找操作优先使用find()而非operator[],避免意外插入
  2. 插入大量数据时,考虑预先构造vector再转为map
  3. 使用emplace()替代insert()可避免不必要的拷贝
  4. 对于频繁查找但不需排序的场景,考虑使用unordered_map
相关推荐
blasit5 小时前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
肆忆_1 天前
# 用 5 个问题学懂 C++ 虚函数(入门级)
c++
不想写代码的星星1 天前
虚函数表:C++ 多态背后的那个男人
c++
端平入洛3 天前
delete又未完全delete
c++
端平入洛4 天前
auto有时不auto
c++
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1235 天前
matlab画图工具
开发语言·matlab
dustcell.5 天前
haproxy七层代理
java·开发语言·前端
norlan_jame5 天前
C-PHY与D-PHY差异
c语言·开发语言
哇哈哈20215 天前
信号量和信号
linux·c++