c++ stl容器之map用法
目录
(1)map介绍
(2)map、multimap、unordered_map区别
(3)map用法
1.map接口表
2.使用举例
插入数据与遍历数据
查找关键字和值
删除元素
按照值排序
(4)multimap用法
(5)unordered_map用法
(1)map介绍
map是STL的一个关联容器,以键值对存储的数据,其类型可以自己定义,每个关键字在map中只能出现一次,关键字不能修改,值可以修改。
map同set、multiset、multimap内部数据结构都是红黑树,而java中的hashmap是以hash table实现的。所以map内部有序(自动排序,单词时按照字母序排序),查找时间复杂度为O(logn)。
multimap与map的差别仅在于multimap允许键重复,有多个相同的键,而map要求键的唯一性。
(2)map、multimap、unordered_map区别
在C++中,std::map和std::unordered_map都是关联容器,它们存储的元素都是键值对(key-value pairs),并且每个键在容器中都是唯一的。然而,它们在内部实现、性能特性以及适用场景上有所不同。
对于std::map(基于红黑树实现),insert()函数会保持元素的排序顺序。而对于std::unordered_map(基于哈希表实现),元素的顺序是随机的。
主要区别如下表:
特性 | std::map | std::multimap | std::unordered_map |
键的唯一性 | 键唯一(不允许重复) | 键可重复(允许重复) | 键唯一(不允许重复) |
元素有序性 | 按键升序排序(红黑树实现) | 按键升序排序(红黑树实现) | 无序(哈希表实现) |
查找复杂度 | O(log N) | O(log N) | 平均 O(1),最坏 O(N)(哈希冲突) |
插入/删除复杂度 | O(log N) | O(log N) | 平均 O(1),最坏 O(N)(哈希冲突) |
适用场景 | 需要有序遍历或范围查询 | 需要有序遍历且键可重复 | 需要快速查找且不关心顺序 |
在选择使用std::map还是std::unordered_map时,你需要考虑你的具体需求。如果你需要元素保持排序或者对迭代器稳定性有要求,那么应该使用std::map。如果你对性能有严格要求,并且可以接受非确定性的迭代顺序,那么应该使用std::unordered_map。
(3)map用法
1.map接口表
操作 | 示例 |
构造对象 | #include <map> // 第一种 map<string,int> mymap1; // 也可以这样 typedef map<string,int> My_Map; My_Map mymap2; |
insert() 插入数据 | 插入单个元素 std::map<int, std::string> myMap; myMap.insert(std::pair<int, std::string>(1, "one")); // 或者使用make_pair myMap.insert(std::make_pair(2, "two")); // 或者使用初始化列表(C++11及更高版本) myMap.insert({3, "three"}); |
检查是否插入成功 auto result = myMap.insert(std::pair<int, std::string>(1, "one")); if (result.second == false) { // 插入失败,键1已存在 } | |
插入多个元素 std::vector<std::pair<int, std::string>> elements = {{4, "four"}, {5, "five"}}; myMap.insert(elements.begin(), elements.end()); // 或者使用初始化列表(C++11及更高版本) myMap.insert({{6, "six"}, {7, "seven"}}); | |
从C++11开始,std::map和std::unordered_map都提供了emplace()函数,该函数允许你直接在容器中构造元素,这通常比先构造一个临时对象然后再插入更高效。 myMap.emplace(1, "one"); // 直接在map中构造元素 | |
find() 查找元素 | // 查找键为2的元素 auto it = myMap.find(2); if (it != myMap.end()) { // 找到 } else { std::cout << "Key 2 not found." << std::endl; } |
clear() 清空元素 | // 清除映射中的所有元素 myMap.clear(); |
erase() 删除一个元素 | myMap.erase(2); // 移除键为2的元素 |
auto it = myMap.find(3); // 查找键为3的元素的迭代器 if (it != myMap.end()) { myMap.erase(it); // 移除找到的元素 } | |
// 假设我们想移除所有键在2到4(包括2但不包括4)之间的元素 auto range_start = myMap.lower_bound(2); // 找到第一个不小于2的元素的迭代器 auto range_end = myMap.upper_bound(4); // 找到第一个大于4的元素的迭代器 myMap.erase(range_start, range_end); // 移除范围内的元素 | |
erase()会返回指向下一个有效元素的迭代器。 | |
my_map.size() | map的长度大小 |
my_map.begin() | 返回指向map头部的迭代器 |
my_map.end() | 返回指向map末尾的迭代器 |
my_map.rbegin() | 返回一个指向map尾部的逆向迭代器 |
my_map.rend() | 返回一个指向map头部的逆向迭代器 |
my_map.empty() | map为空时返回true |
swap() | 交换两个map,两个map中所有元素都交换 |
2.使用举例
插入数据与遍历数据
通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据iterator->first和iterator->second,分别代表关键字和value值。
在C++中,std::map默认就是按照键(key)的升序进行排序和存储的。因此,你只需要使用标准的迭代器来遍历std::map,就可以按照键的升序来获取元素。
#include <iostream>
using namespace std;#include <map>// 自定义打印map的函数
void printMap(map<string, int> mymymap)
{cout << "----------" << endl;map<string, int>::iterator it;for (it = mymymap.begin(); it != mymymap.end(); it++)cout << it->first << "=" << it->second << endl; // key=valuecout << "----------" << endl;
}int main()
{map<string, int> mymap;//第一种:用insert函数插入pair数据mymap.insert(pair<string, int>("first", 1));mymap.insert(pair<string, int>("second", 2));//第二种:用insert函数插入value_type数据mymap.insert(map<string, int>::value_type("third", 3));mymap.insert(map<string, int>::value_type("fourth", 4));//迭代器遍历map<string, int>::iterator it;cout << "----------" << endl;for (it = mymap.begin(); it != mymap.end(); it++)cout << it->first << "=" << it->second << endl; // key=valuecout << "----------" << endl;//第三种:更简便mymap["first"] = 100;mymap["fifth"] = 5; //新加入的元素会被放到容器的第一个位置printMap(mymap);return 0;
}
查找关键字和值
第一种:用count函数来判断关键字是否出现,其缺点是无法定位元素出现的位置。由于map一对一的映射关系,count函数的返回值要么是0,要么是1。
#include <iostream>
using namespace std;#include <map>int main()
{map<string, int> my_map;my_map["first"] = 1;cout << my_map.count("first") << endl; //输出1cout << my_map.count("second") << endl; //输出0return 0;
}
第二种:用find函数来定位元素出现的位置,它返回一个迭代器,当数据出现时,返回的是数据所在位置的迭代器;若map中没有要查找的数据,返回的迭代器等于end函数返回的迭代器。
#include <map>
#include <string>
#include <iostream>using namespace std;int main()
{map<int, string> my_map;my_map.insert(pair<int, string>(1, "student_one"));my_map.insert(pair<int, string>(2, "student_two"));my_map.insert(pair<int, string>(3, "student_three"));map<int, string>::iterator it;it = my_map.find(1);if (it != my_map.end())cout << "Find, the value is " << it->second << endl;elsecout << "Do not Find" << endl;it = my_map.find(4);if (it != my_map.end())cout << "Find, the value is " << it->second << endl;elsecout << "Do not Find" << endl;return 0;
}
删除元素
map对象的erase函数传入参数即可以是迭代器又可以是key
#include <map>
#include <string>
#include <iostream>using namespace std;void printMap(map<int, string> mymymap)
{cout << "----------" << endl;map<int, string>::iterator it;for (it = mymymap.begin(); it != mymymap.end(); it++)cout << it->first << "=" << it->second << endl; // key=valuecout << "----------" << endl;
}int main()
{map<int, string> my_map;my_map.insert(pair<int, string>(1, "one"));my_map.insert(pair<int, string>(2, "two"));my_map.insert(pair<int, string>(3, "three"));my_map.insert(pair<int, string>(4, "fourth"));printMap(my_map);// 第1种,用迭代器删除 关键字为 1 的数据map<int, string>::iterator it;it = my_map.find(1);my_map.erase(it); //如果要删除1,用关键字删除printMap(my_map);// 第2种,直接用关键字删除int n = my_map.erase(2); //如果成功删除了会返回1,否则返回0printMap(my_map);// 第2种,用迭代器,成片的删除,可以达到直接清空所有数据my_map.erase(my_map.begin(), my_map.end());// 成片删除要注意的是,也是STL的特性,删除区间是一个左闭右开的集合printMap(my_map);return 0;
}
按照值排序
map中元素是自动按key升序排序(从小到大)的;按照value排序时,想直接使用sort函数是做不到的,sort函数只支持数组、vector、list、queue等的排序,无法对map排序,那么就需要把map放在vector中,再对vector进行排序。
例子1
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;void printMap(map<string, int> mymymap)
{cout << "----------" << endl;map<string, int>::iterator it;for (it = mymymap.begin(); it != mymymap.end(); it++)cout << it->first << "=" << it->second << endl; // key=valuecout << "----------" << endl;
}bool cmp(pair<string, int> a, pair<string, int> b)
{return a.second < b.second; // 严格升序
}int main()
{map<string, int> ma;ma["Alice"] = 86;ma["Bob"] = 78;ma["Zip"] = 92;ma["Stdevn"] = 88;printMap(ma);// 第一种方式传递到vector中vector<pair<string, int>> vec(ma.begin(), ma.end());// 第二种方式传递到vector中vector<pair<string, int>> vec2;for (map<string, int>::iterator it = ma.begin(); it != ma.end(); it++)vec2.push_back(pair<string, int>(it->first, it->second));// std::pair<std::string, int> tempPair(name, grade); // 对vec排序sort(vec.begin(), vec.end(), cmp);for (vector<pair<string, int>>::iterator it = vec.begin(); it != vec.end(); ++it){cout << it->first << "=" << it->second << endl;}return 0;
}
例子2
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <functional> bool judge_func(const std::pair<int, std::string>& a, const std::pair<int, std::string>& b){return a.second < b.second; // 严格弱序比较// 等值的元素在排序后的序列中保持其原始相对顺序// return a.second <= b.second; // 非严格弱序比较// 在大多数情况下,你应该使用严格弱序比较(即a.second < b.second)来确保排序的稳定性和可预测性
}int main() { std::map<int, std::string> m = {{1, "Z"}, {2, "B"}, {3, "A"}, {4, "C"}}; std::vector<std::pair<int, std::string>> v(m.begin(), m.end()); // c++中sort方法使用匿名函数排序// [](参数a, 参数b){函数体返回bool, a.x < b.x /*返回true表示升序*/}// std::sort(v.begin(), v.end(), [](const std::pair<int, std::string>& a, const std::pair<int, std::string>& b) { // return a.second < b.second; // }); // 有名函数排序std::sort(v.begin(), v.end(), judge_func);// 输出排序后的结果 for (const auto& pair : v) { std::cout << pair.first << ": " << pair.second << std::endl; } return 0;
}
(4)multimap用法
multimap是关联式容器,按照特定顺序存储键值对<key、value>,其中多个键值对之间的key可以重复。
multimap与map唯一不同就是,map中key是唯一的,multimap中key是可以重复的。
Multimap 案例:
- 1个key值可以对应多个valude =分组
- 公司有销售部 sale (员工2名)、技术研发部 development (2人)、财务部 Financial (2人)
- 人员信息有:姓名,年龄,电话、工资等组成
- 通过 multimap进行 信息的插入、保存、显示
- 分部门显示员工信息
- 按条件搜索修改
#include <iostream>
#include <string>
#include <map>
using namespace std;class Person
{
public:string name;int age;string telephone;double salary;
};void test()
{Person p1, p2, p3, p4, p5, p6;p1.name = "王1";p1.age = 31;p2.name = "王2";p2.age = 32;p3.name = "张3";p3.age = 33;p4.name = "赵4";p4.age = 35;p5.name = "张5";p5.age = 34;p6.name = "赵6";p6.age = 35;// 1.构造multimap<string, Person> map2;// 2.插入数据//sale部门map2.insert(make_pair("sale", p1) );map2.insert(make_pair("sale", p2) );//development 部门map2.insert(make_pair("development", p3) );map2.insert(make_pair("development", p5) );//Financial 部门map2.insert(make_pair("Financial", p4) );map2.insert(make_pair("Financial", p6) );// 3.遍历multimap类型multimap<string, Person>::iterator it = map2.begin();for (it; it != map2.end(); it++){cout << it->first << "\t" << it->second.name << endl;}/*Financial 赵4Financial 赵6development 张3development 张5sale 王1sale 王2*/// 4.统计development部门的人数int num2 = map2.count("development");cout << "development num = " << num2 << endl; // 2// 5.查找development部门员工信息// find若查找到则出现在第一次位置,若未查找到则map2.end()multimap<string, Person>::iterator it2 = map2.find("development");int tag = 0;while (it2 != map2.end() && tag < num2){cout << it2->first << "\t" << it2->second.name << endl;it2++;tag++;}/*development 张3development 张5*/// 可以注意到multimap会将同一个key的多个value挨着// 所以这里用find方法得到的迭代器再++时,全是development部门的值// 6.按照条件 检索数据 进行修改cout << "-----------------" << endl;for(multimap<string, Person>::iterator it=map2.begin(); it!=map2.end(); it++){if (it->second.age == 32 ){it->second.name = "name32";}}for( multimap<string, Person>::iterator it=map2.begin(); it!=map2.end(); it++){cout << it->first << "\t" << it->second.age << "\t" << it->second.name << endl;}/*Financial 35 赵4Financial 35 赵6development 33 张3development 34 张5sale 31 王1sale 32 name32*/
}int main()
{test();return 0;
}
(5)unordered_map用法
- 键唯一性:每个键只能出现一次,重复插入会覆盖原有值。
- 无序性:元素存储顺序不确定(由哈希函数决定)。
- 底层实现:基于哈希表(哈希桶 + 链表或树)。
适用场景:
需要快速查找、插入或删除,且不关心顺序。示例:缓存系统、字典查询。
例子
#include <unordered_map>
#include <iostream>int main() {std::unordered_map<int, std::string> umap = {{1, "Alice"},{2, "Bob"},{3, "Charlie"}};// 输出顺序不确定(可能是 2, 3, 1 或其他)for (const auto& [key, value] : umap) {std::cout << key << ": " << value << std::endl;}// 可能的输出:// 2: Bob// 3: Charlie// 1: Alice
}
end