C 的Pair用法分类整理(精)

本文详细介绍了C++标准模板库中的Pair类型,包括其定义、构造方式、成员变量及使用方法。并展示了如何通过make_pair函数创建Pair对象,以及Pair在实际编程中的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 pair的应用

pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。

2 make_pair函数

template pair make_pair(T1 a, T2 b) { return pair(a, b); }

很明显,我们可以使用pair的构造函数也可以使用make_pair来生成我们需要的pair。 一般make_pair都使用在需要pair做参数的位置,可以直接调用make_pair生成pair对象很方便,代码也很清晰。 另一个使用的方面就是pair可以接受隐式的类型转换,这样可以获得更高的灵活度。灵活度也带来了一些问题如:

std::pair<int, float>(1, 1.1);

std::make_pair(1, 1.1);

是不同的,第一个就是float,而第2个会自己匹配成double。

类模板:template <class T1, class T2> struct pair

参数:T1是第一个值的数据类型,T2是第二个值的数据类型。

功能:pair将一对值组合成一个值,这一对值可以具有不同的数据类型(T1和T2),两个值可以分别用pair的两个公有函数first和second访问。

具体用法:

1.定义(构造):

1 pair<int, double> p1; //使用默认构造函数

2 pair<int, double> p2(1, 2.4); //用给定值初始化

3 pair<int, double> p3(p2); //拷贝构造函数
1 pair<int, double> p1; //使用默认构造函数
2 p1.first = 1;

3 p1.second = 2.5;

4 cout << p1.first << ' ' << p1.second << endl;

 
(1)利用make_pair:

1 pair<int, double> p1;
2 p1 = make_pair(1, 1.2);

(2)变量间赋值:

pair<int, double> p1(1, 1.2);

pair<int, double> p2 = p1;

Pair类型概述
    pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同,基本的定义如下:
    pair<int, string> a;
    表示a中有两个类型,第一个元素是int型的,第二个元素是string类型的,如果创建pair的时候没有对其进行初始化,则调用默认构造函数对其初始化。
    pair<string, string> a("James", "Joy");
    也可以像上面一样在定义的时候直接对其初始化。
    由于pair类型的使用比较繁琐,因为如果要定义多个形同的pair类型的时候,可以时候typedef简化声明:
    typedef pair<string, string> author;
    author pro("May", "Lily");
    author joye("James", "Joyce");
Pair对象的操作
    对于pair类,由于它只有两个元素,分别名为first和second,因此直接使用普通的点操作符即可访问其成员生成新的pair对象
    pair<string, string> a("Lily", "Poly"); 
    string name;
    name = pair.second;
    可以使用make_pair对已存在的两个数据构造一个新的pair类型:
    int a = 8;
    string m = "James";
    pair<int, string> newone;
    newone = make_pair(a, m);

转自https://blog.youkuaiyun.com/zhuangtongy/article/details/80264064

<think>好的,用户现在让我详细整理C++中map的用法。首先,我需要回忆一下用户之前的对话历史。之前他们询问了关于Python爱心代码的高级实现,涉及动画和绘图,可能对编程有一定的基础。现在转向C++的map,说明他们可能在学习数据结构或者需要用到关联容器。 用户的问题是关于C++ map的用法,需要详细整理。我需要考虑用户可能的水平,他们可能已经了解基础,但需要系统化的总结。首先,我应该从map的基本概念开始,解释它是关联容器,存储键值对,按键排序,以及底层通常是红黑树实现。 接下来,用户可能需要知道如何包含头文件、初始化、插入元素。插入元素的方法有insert、emplace、以及使用operator[],这些的区别和适用场景需要说明清楚。比如,insert返回的是pair,而emplace可以原地构造,可能更高效。operator[]在键不存在时会自动插入,这可能引发一些需要注意的问题。 然后是元素的访问,operator[]和at()的区别,比如at()在键不存在时会抛出异常,而operator[]会插入默认值。这点需要强调,避免用户在使用时出现意外。 遍历部分,需要演示如何使用迭代器,包括C++11的range-based for循环,这样用户更容易理解和应用。同时,查找元素的方法,find和count的区别,以及lower_bound和upper_bound的使用场景,比如在范围查询时有用。 删除元素方面,erase有几种用法,可以通过迭代器、键或者范围来删除。需要说明返回值的不同,比如erase(key)返回删除的元素个数,对于map来说只能是0或1。 容量查询部分,empty()和size()比较基础,但需要提及。高级特性部分,自定义比较函数可能对用户有用,特别是当键是自定义类型时。还有extract和merge这些C++17的新特性,如果用户使用的是较新的编译器,这些功能可能很有帮助。 性能分析也是重要的一部分,需要指出map的查找、插入、删除操作的时间复杂度是O(log n),基于红黑树的实现,适合需要有序且频繁查找的场景。与unordered_map的对比可以帮助用户选择合适的容器。 最后,总结使用场景,强调当需要有序键或者频繁使用范围查询时选择map,否则考虑unordered_map。同时,给出示例代码,帮助用户更好地理解各个方法的实际应用。 需要检查是否有遗漏的部分,比如是否覆盖了所有常用的成员函数,是否解释了常见错误和注意事项,比如使用operator[]可能意外插入元素。另外,考虑到用户之前问的是Python代码,可能对C++的模板和迭代器不太熟悉,需要用更清晰易懂的语言解释,避免过于技术化的术语,同时提供示例代码来辅助说明。</think>以下是关于C++标准库中`std::map`的详细用法整理,包含基本操作和高级特性,以清晰的逻辑结构呈现: --- ### **一、基本概念** `std::map`是**有序关联容器**,存储键值对(`key-value`),满足以下特性: - 键唯一(`key`不可重复) - 按键**自动排序**(默认按`key`升序排列,可自定义) - 底层实现:红黑树(平衡二叉搜索树) --- ### **二、头文件与初始化** ```cpp #include <map> using namespace std; // 初始化方式 map<string, int> m1; // 空map map<int, string> m2 = {{1, "A"}, {2, "B"}}; // 列表初始化 map<char, double> m3(m2.begin(), m2.end()); // 通过迭代器范围初始化 ``` --- ### **三、核心操作** #### 1. **插入元素** | 方法 | 描述 | |--------------------|----------------------------------------------------------------------| | `insert(pair)` | 插入键值对,返回`pair<iterator, bool>`(插入成功时`bool=true`) | | `emplace(args...)` | 原地构造元素(更高效),如`m.emplace(3, "C")` | | `operator[]` | 若`key`不存在则插入默认值,如`m["key"] = 5` | **示例:** ```cpp m1.insert({"apple", 3}); // 插入pair m1.emplace("banana", 5); // 直接构造 m1["cherry"] = 7; // 使用[]赋值 ``` --- #### 2. **访问元素** | 方法 | 描述 | |------------------|-------------------------------------------------------------------| | `operator[]` | 返回`key`对应的`value`,若`key`不存在则插入默认值 | | `at(key)` | 返回`key`对应的`value`,若`key`不存在则抛出`out_of_range`异常 | | `find(key)` | 返回指向元素的迭代器,未找到则返回`end()` | | `count(key)` | 返回`key`的出现次数(对map只能是0或1) | **示例:** ```cpp cout << m1["apple"]; // 输出3(若不存在会插入默认值) cout << m1.at("banana"); // 输出5(若不存在抛异常) auto it = m1.find("cherry"); if (it != m1.end()) cout << it->second; // 安全访问 ``` --- #### 3. **遍历元素** ```cpp // 迭代器遍历 for (auto it = m1.begin(); it != m1.end(); ++it) { cout << it->first << ": " << it->second << endl; } // C++11范围for循环 for (const auto& [key, value] : m1) { // 结构化绑定 cout << key << ": " << value << endl; } ``` --- #### 4. **删除元素** | 方法 | 描述 | |---------------------|--------------------------------------------------| | `erase(iterator)` | 删除迭代器指向的元素 | | `erase(key)` | 删除指定`key`的元素,返回删除数量(0或1) | | `erase(first, last)`| 删除迭代器范围内的元素 | **示例:** ```cpp m1.erase("apple"); // 删除键为"apple"的元素 auto it = m1.find("banana"); if (it != m1.end()) m1.erase(it); // 通过迭代器删除 m1.erase(m1.begin(), m1.end()); // 清空map ``` --- #### 5. **容量查询** | 方法 | 描述 | |---------------|---------------------------| | `empty()` | 判断map是否为空 | | `size()` | 返回元素个数 | | `max_size()` | 返回可容纳的最大元素数量 | --- ### **四、高级特性** #### 1. **自定义排序规则** ```cpp // 按key降序排列 struct Compare { bool operator()(const int& a, const int& b) const { return a > b; } }; map<int, string, Compare> m4; ``` #### 2. **范围查询** ```cpp auto lower = m1.lower_bound("b"); // 第一个 >= "b"的键 auto upper = m1.upper_bound("d"); // 第一个 > "d"的键 for (auto it = lower; it != upper; ++it) { // 遍历键在[b, d)范围内的元素 } ``` #### 3. **C++17新特性** - **`extract()`**:提取元素(不触发拷贝构造) ```cpp auto node = m1.extract("apple"); if (!node.empty()) m2.insert(std::move(node)); ``` - **`merge()`**:合并两个map ```cpp map<int, string> m5; m1.merge(m5); // 将m5中元素移动到m1,重复key保留原值 ``` --- ### **五、性能分析** - **时间复杂度**(基于红黑树): - 查找、插入、删除:$O(\log n)$ - **适用场景**: - 需要有序遍历键 - 频繁基于键的确查找 - **对比`unordered_map`**: - `unordered_map`(哈希表)查找$O(1)$,但无序 --- ### **六、示例代码** ```cpp #include <iostream> #include <map> using namespace std; int main() { map<string, int> scores = {{"Alice", 90}, {"Bob", 85}}; // 插入 scores.insert({"Charlie", 88}); scores.emplace("Dave", 92); scores["Eve"] = 95; // 删除 scores.erase("Bob"); // 遍历 for (const auto& [name, score] : scores) { cout << name << ": " << score << endl; } // 查找 if (scores.count("Alice")) { cout << "Alice's score: " << scores.at("Alice") << endl; } return 0; } ``` --- ### **七、常见问题** 1. **键类型要求**:必须支持`<`运算符或自定义比较器 2. **`operator[]`的风险**:若键不存在会插入默认值,可能意外修改map 3. **迭代器失效**:仅删除操作会导致指向被删元素的迭代器失效 希望这份整理能帮助您系统掌握`std::map`的用法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值