MENU

C++STL 中 map 的使用策略(一)

March 13, 2018 • Read: 4640 • c/c++阅读设置

Map 是 STL 的一个关联容器,它提供一对一的数据处理能力。比如有一个姓名的集合 {"Tom", "Jone", "Mary"},班级集合 {1, 2},班级与姓名可能存在以下的映射关系:

  • class("Tom") = 2
  • class("Jone") = 2
  • class("Mary") = 1

我们称其中的姓名集合为关键字集合(key),班级集合为值集合(value

构造一个集合展开目录

  • map<T1,T2> m;//名为m的,从T1类型到T2类型的映射

插入元素展开目录

  • #include <map>
  • #include <string>
  • using namespace std;
  • int main() {
  • map<string, int> dict;
  • dict.insert(pair<string, int>("Tom", 1)); // {"Tom"->1}
  • dict.insert(pair<string, int>("Jone", 2)); // {"Tom"->1, "Jone"->2}
  • dict.insert(pair<string, int>("Mary", 1)); // {"Tom"->1, "Jone"->2, "Mary"->1}
  • dict.insert(pair<string, int>("Tom", 2)); // {"Tom"->1, "Jone"->2, "Mary"->1}
  • return 0;
  • }

在 C++ 中通过 insert() 方法向集合中插入一个新的映射,参数是一个 pair 类型的结构。这个 pair 是另一个 STL 模板 —— 元祖pair<int,char> (1,'a') 定义了一个整数 1 和字符 a 的 pair。我们向映射中加入新映射对的时候就是通过 pair 来实现的。如果插入的 key 之前已经有 value,不会用插入的新的 value 替代原来的 value,而是直接插入无效,但并不会报错

如果插入语句没有生效,那么这就涉及到我们怎么知道 insert 语句是否插入成功的问题了,可以通过 pair 来获得是否插入成功,程序如下:

  • pair<map<int, string>::iterator, bool> insert_pair;
  • insert_pair = mapStudent.insert(map<int, string>::value_type (1, "student_one"));

我们通过 pair 的第二个变量来知道是否插入成功,它的第一个变量返回的是一个 map 迭代器,如果插入成功的话,insert_pair.second 应该是 true,否则为 false。

  • #include <bits/stdc++.h>
  • using namespace std;
  • int main()
  • {
  • map<int, string> mapStudent;
  • pair<map<int, string>::iterator, bool> insert_Pair;
  • insert_Pair = mapStudent.insert(pair<int, string>(1, "student_one"));
  • if(insert_Pair.second == true)
  • {
  • cout<<"Insert Successfully"<<endl;
  • }
  • else
  • {
  • cout<<"Insert Failure"<<endl;
  • }
  • insert_Pair = mapStudent.insert(pair<int, string>(1, "student_two"));
  • if(insert_Pair.second == true)
  • {
  • cout<<"Insert Successfully"<<endl;
  • }
  • else
  • {
  • cout<<"Insert Failure"<<endl;
  • }
  • map<int, string>::iterator iter;
  • for(insert_Pair.first = mapStudent.begin(); insert_Pair.first != mapStudent.end(); insert_Pair.first++)
  • cout<<insert_Pair.first -> first<<" "<<insert_Pair.first -> second<<endl;
  • }

那么现在问题来了,如果想要覆盖掉原有的值,应该怎么办呢?用数组的访问方式!

  • //验证数组形式插入数据的效果
  • #include <map>
  • #include <string>
  • #include <iostream>
  • using namespace std;
  • int main()
  • {
  • map<int,string> mapStudent;
  • mapStudent[3] = "student_one";
  • mapStudent[1] = "student_two";
  • mapStudent[3] = "student_three";
  • map<int, string>::iterator iter;
  • for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
  • cout<<iter->first<<' '<<iter->second<<endl;
  • }

访问映射展开目录

C++ 访问映射和数组一样,直接用 [] 就能访问,比如 dict["Tom"] 就可以获取 "Tom" 的班级。而这里有一个比较特殊的地方,如果没有对 "Tom" 做过映射的话,此时你访问 dict["Tom"],系统将会自动为 "Tom" 生成一个映射,其 value 为对应类型的默认值。当然有些时候我们不希望系统自动为我们生成映射,这时候我们需要检测 "Tom" 是否有映射。需要用到 count() 函数进行判断

  • #include <map>
  • #include <string>
  • #include <stdio.h>
  • using namespace std;
  • int main() {
  • map<string, int> dict; // {}
  • dict["Tom"] = 1; // {"Tom"->1}
  • dict["Jone"] = 2; // {"Tom"->1, "Jone"->2}
  • //dict["Mary"] = 1; // {"Tom"->1, "Jone"->2, "Mary"->1}
  • if (dict.count("Mary"))
  • printf("Mary is in class %d\n", dict["Mary"]);
  • else
  • printf("Mary has no class");
  • return 0;
  • }

遍历映射展开目录

可以通过迭代器访问映射中的每对映射,每个迭代器的 first 值对应 key,second 对应 value

  • #include <map>
  • #include <string>
  • #include <iostream>
  • using namespace std;
  • int main() {
  • map<string, int> dict; // {}
  • dict["Tom"] = 1; // {"Tom"->1}
  • dict["Jone"] = 2; // {"Tom"->1, "Jone"->2}
  • dict["Mary"] = 1; // {"Tom"->1, "Jone"->2, "Mary"->1}
  • for (map<string, int>::iterator it = dict.begin(); it != dict.end(); ++it)
  • cout << it->first << " is in class " << it->second << endl;
  • return 0;
  • }

删除元素展开目录

移除 map 中某个值用 erase(),它有三个重载函数,下面的示例详细说明了它的用法

  • #include <bits/stdc++.h>
  • using namespace std;
  • int main()
  • {
  • map<int, string> mapStudent;
  • mapStudent.insert(pair<int, string>(1, "student_one"));
  • mapStudent.insert(pair<int, string>(2, "student_two"));
  • mapStudent.insert(pair<int, string>(3, "student_three"));
  • //如果你要演示输出效果,请选择以下的一种,你看到的效果会比较好
  • //如果要删除1,用迭代器删除
  • map<int, string>::iterator iter;
  • iter = mapStudent.find(1);
  • mapStudent.erase(iter);
  • //如果要删除1,用关键字删除
  • int n = mapStudent.erase(1);//如果删除了会返回1,否则返回0
  • //用迭代器,成片的删除
  • //一下代码把整个map清空
  • mapStudent.erase( mapStudent.begin(), mapStudent.end() );
  • //成片删除要注意的是,也是STL的特性,删除区间是一个前闭后开的集合
  • }

以上只是我列举一些 map 常用的方法,如果需要更多的功能,可以查看 api

Last Modified: February 8, 2020
Archives Tip
QR Code for this page
Tipping QR Code