STL容器之map
【1】map容器
map 是关联容器。容器中的每一个元素都是由一个键值和一个数据值组成的。
set 是一个集合它以其元素作为键值(同一个键值只能出现一次),且默认以升序排列。
list 是一个顺序容器。
【2】map容器使用方法以及实例
(1)定义、插入数据方法实例
1 // map容器定义、插入数据方式代码 2 #include<map> 3 #include<string> 4 #include<iostream> 5 using namespace std; 6 7 // 打印map容器数据 8 void print(map<int, string>& mapStu, int nValue) 9 { 10 cout << "mapStu" << nValue << "数据信息:" << endl; 11 cout << "size: " << mapStu.size() << endl; 12 map<int, string>::iterator iter = mapStu.begin(); 13 for (; iter != mapStu.end(); ++iter) 14 { 15 cout << "key: " << iter->first << " value: " << iter->second << endl; 16 } 17 cout << endl; 18 } 19 20 void main() 21 { 22 // 第一种定义map的方法 23 map<int, string> mapStu1; 24 // 第二种定义map的方法 25 typedef map<int, string> mapType; 26 mapType mapStu2, mapStu3, mapStu4; 27 28 // 第一种插入数据方法:用insert函数插入value_type数据 29 mapStu1.insert(map<int, string>::value_type(1, "Qin")); 30 mapStu1.insert(map<int, string>::value_type(2, "Sun")); 31 mapStu1.insert(map<int, string>::value_type(3, "Wang")); 32 mapStu1.insert(map<int, string>::value_type(2, "Zhao")); 33 print(mapStu1, 1); 34 // 第二种插入数据方法:用insert函数插入pair数据 35 mapStu2.insert(pair<int, string>(1, "Qin")); 36 mapStu2.insert(pair<int, string>(2, "Sun")); 37 mapStu2.insert(pair<int, string>(3, "Wang")); 38 mapStu2.insert(pair<int, string>(2, "Zhao")); 39 print(mapStu2, 2); 40 // 第三种插入数据方法:用insert函数插入make_pair数据 41 mapStu3.insert(make_pair<int, string>(1, "Qin")); 42 mapStu3.insert(make_pair<int, string>(2, "Sun")); 43 mapStu3.insert(make_pair<int, string>(3, "Wang")); 44 mapStu3.insert(make_pair<int, string>(2, "Zhao")); 45 print(mapStu3, 3); 46 // 第四种插入数据方法:数组插入法 47 mapStu4[1] = "Qin"; 48 mapStu4[2] = "Sun"; 49 mapStu4[3] = "Wang"; 50 mapStu4[2] = "Zhao"; 51 print(mapStu4, 4); 52 53 pair<map<int, string>::iterator, bool> iter_pair; 54 iter_pair = mapStu1.insert(map<int, string>::value_type(3, "Li")); 55 cout << "插入成功与否:" << iter_pair.second << endl; 56 57 system("pause"); 58 } 59 60 // run out 61 /* 62 mapStu1数据信息: 63 size: 3 64 key: 1 value: Qin 65 key: 2 value: Sun 66 key: 3 value: Wang 67 68 mapStu2数据信息: 69 size: 3 70 key: 1 value: Qin 71 key: 2 value: Sun 72 key: 3 value: Wang 73 74 mapStu3数据信息: 75 size: 3 76 key: 1 value: Qin 77 key: 2 value: Sun 78 key: 3 value: Wang 79 80 mapStu4数据信息: 81 size: 3 82 key: 1 value: Qin 83 key: 2 value: Zhao 84 key: 3 value: Wang 85 86 插入成功与否:0 87 请按任意键继续. . . 88 */
分析总结:
以上四种用法,虽然都可以实现数据的插入,但是它们是有区别的。
当然,第一、二、三种在效果上是完全一样的,用insert函数插入数据,在数据的插入过程中涉及到集合的唯一性这个概念:
即当map中有这个关键字时,insert操作再插入数据是不会成功的。
但是,用数组(第四种)方式就不同了,它可以覆盖以前该关键字对应的值,用程序说明如下:
mapStu1.insert(map<int, string>::value_type(2, "Sun"));
mapStu1.insert(map<int, string>::value_type(2, "Zhao"));
上面这两条语句执行后,mapStu1中2这个关键字对应的值是“Sun”,第二条语句并没有生效。
那么,这就涉及到我们怎么知道insert语句是否插入成功的问题?可以用pair来获得是否插入成功,程序如下:
pair<map<int, string>::iterator, bool> iter_pair;
iter_pair = mapStu1.insert(map<int, string>::value_type(3, "Li"));
我们通过pair的第二个变量来判断是否插入成功,它的第一个变量返回的是一个map的迭代器,
如果插入成功的话迭代器的变量iter_pair.second应该是true,否则为false。
(2)遍历map容器的三种方式
程序代码如下:
1 #include <map> 2 #include <iostream> 3 #include <string> 4 using namespace std; 5 6 // 第一种方式 7 void print1(map<int, string>& mapStu) 8 { 9 cout << "第一种遍历方式:" << endl; 10 cout << "size: " << mapStu.size() << endl; 11 // 迭代map容器中的数据 12 map<int, string>::iterator iter = mapStu.begin(); 13 for (; iter != mapStu.end(); ++iter) 14 { 15 cout << "key: " << iter->first << " value: " << iter->second << endl; 16 } 17 cout << endl; 18 } 19 20 // 第二种方式 21 void print2(map<int, string>& mapStu) 22 { 23 cout << "第二种遍历方式:" << endl; 24 cout << "size: " << mapStu.size() << endl; 25 // 迭代map容器中的数据 26 map<int, string>::reverse_iterator iter = mapStu.rbegin(); 27 for (; iter != mapStu.rend(); ++iter) 28 { 29 cout << "key: " << iter->first << " value: " << iter->second << endl; 30 } 31 32 cout << endl; 33 } 34 35 // 第三种方式 36 void print3(map<int, string>& mapStu) 37 { 38 cout << "第三种遍历方式:" << endl; 39 int nSize = mapStu.size(); 40 cout << "size: " << mapStu.size() << endl; 41 // 迭代map容器中的数据 42 for(int nIndex = 1; nIndex < nSize + 1; ++nIndex) 43 { 44 cout << "<" << nIndex << " :: " << mapStu[nIndex] << ">" << endl; 45 } 46 } 47 48 void main() 49 { 50 typedef map<int, string> mapType; 51 mapType mapStu; 52 53 // 用insert函数插入value_type数据 54 mapStu.insert(map<int, string>::value_type(1, "Qin")); 55 mapStu.insert(map<int, string>::value_type(2, "Sun")); 56 mapStu.insert(map<int, string>::value_type(3, "Wang")); 57 mapStu.insert(map<int, string>::value_type(4, "Zhao")); 58 print1(mapStu); // 第一种方式 59 print2(mapStu); // 第二种方式 60 print3(mapStu); // 第三种方式 61 62 system("pause"); 63 } 64 // run out: 65 /* 66 第一种遍历方式: 67 size: 4 68 key: 1 value: Qin 69 key: 2 value: Sun 70 key: 3 value: Wang 71 key: 4 value: Zhao 72 73 第二种遍历方式: 74 size: 4 75 key: 4 value: Zhao 76 key: 3 value: Wang 77 key: 2 value: Sun 78 key: 1 value: Qin 79 80 第三种遍历方式: 81 size: 4 82 <1 :: Qin> 83 <2 :: Sun> 84 <3 :: Wang> 85 <4 :: Zhao> 86 请按任意键继续. . . 87 */
(3)查找数据的三种方式
应用实例代码如下:
1 // 三种查找数据的方式 2 #include <map> 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 // 第一种方式 8 void print1(map<int, string>& mapStu) 9 { 10 cout << "遍历容器数据:" << endl; 11 cout << "size: " << mapStu.size() << endl; 12 // 迭代map容器中的数据 13 map<int, string>::iterator iter = mapStu.begin(); 14 for (; iter != mapStu.end(); ++iter) 15 { 16 cout << "key: " << iter->first << " value: " << iter->second << endl; 17 } 18 } 19 20 void main() 21 { 22 typedef map<int, string> mapType; 23 mapType mapStu; 24 25 // 用insert函数插入value_type数据 26 mapStu.insert(map<int, string>::value_type(1, "Qin")); 27 mapStu.insert(map<int, string>::value_type(2, "Sun")); 28 mapStu.insert(map<int, string>::value_type(3, "Wang")); 29 mapStu.insert(map<int, string>::value_type(4, "Zhao")); 30 // 第一种查找数据方式 31 // count函数求的是关键字key的个数?key是不能重复的,所以返回只有0和1两种结果。 32 cout << "查找关键字3的结果 : " << mapStu.count(1) << endl; 33 cout << "查找关键字5的结果: " << mapStu.count(5) << endl; 34 // 第二种查找数据方式 35 map<int, string>::iterator iter; 36 iter = mapStu.find(1); 37 if (iter != mapStu.end()) 38 { 39 cout << "Find, the value is " << iter->second << endl; 40 } 41 else 42 { 43 cout << "Do not Find !" << endl; 44 } 45 // 第三种查找数据方式 46 print1(mapStu); 47 iter = mapStu.lower_bound(2); 48 { 49 cout << "lower_bound(2) :: (不小于2) " << iter->second << endl; 50 } 51 52 iter = mapStu.lower_bound(3); 53 { 54 cout << "lower_bound(3) :: (不小于3) " << iter->second << endl; 55 } 56 57 iter = mapStu.upper_bound(2); 58 { 59 cout << "upper_bound(2) :: (大于2) " << iter->second << endl; 60 } 61 62 iter = mapStu.upper_bound(3); 63 { 64 cout << "upper_bound(3) :: (大于3) " << iter->second << endl; 65 } 66 67 pair<map<int, string>::iterator, map<int, string>::iterator> mapPair; 68 mapPair = mapStu.equal_range(2); 69 if (mapPair.first == mapPair.second) 70 { 71 cout << "equal_range(2) :: Do not Find!" << endl; 72 } 73 else 74 { 75 cout << "equal_range(2) :: Find!" << endl; 76 } 77 78 mapPair = mapStu.equal_range(5); 79 if (mapPair.first == mapPair.second) 80 { 81 cout << "equal_range(5) :: Do not Find!" << endl; 82 } 83 else 84 { 85 cout << "equal_range(5) :: Find!" << endl; 86 } 87 88 system("pause"); 89 } 90 // run out: 91 /* 92 查找关键字3的结果 : 1 93 查找关键字5的结果: 0 94 Find, the value is Qin 95 遍历容器数据: 96 size: 4 97 key: 1 value: Qin 98 key: 2 value: Sun 99 key: 3 value: Wang 100 key: 4 value: Zhao 101 lower_bound(2) :: (不小于2) Sun 102 lower_bound(3) :: (不小于3) Wang 103 upper_bound(2) :: (大于2) Wang 104 upper_bound(3) :: (大于3) Zhao 105 equal_range(2) :: Find! 106 equal_range(5) :: Do not Find! 107 请按任意键继续. . . 108 */
注意:
lower_bound(x)不是下界,而是大于等于x的最小值。
upper_bound(x) 大于x的最小值。
(4)查询、修改、删除、大小、比较、清空、判空等等方法。
应用实例代码如下:
1 #include <map> 2 #include <string> 3 #include <iostream> 4 using namespace std; 5 6 // 打印map容器数据 7 void print(map<int, string>& mapStu) 8 { 9 cout << "size: " << mapStu.size() << endl; 10 // 迭代map容器中的数据 11 map<int, string>::iterator iter = mapStu.begin(); 12 for (; iter != mapStu.end(); ++iter) 13 { 14 cout << "key: " << iter->first << " value: " << iter->second << endl; 15 } 16 cout << endl; 17 } 18 19 void main() 20 { 21 typedef map<int, string> mapType; 22 mapType mapStu1; 23 24 // 用insert函数插入value_type数据 25 mapStu1.insert(map<int, string>::value_type(1, "Qin")); 26 mapStu1.insert(map<int, string>::value_type(2, "Sun")); 27 mapStu1.insert(map<int, string>::value_type(3, "Wang")); 28 mapStu1.insert(map<int, string>::value_type(2, "Zhao")); 29 print(mapStu1); 30 // 查找数据的两种方式: 31 // 方式1: 32 string str2 = mapStu1[2]; 33 cout << str2 << endl; 34 // 方式2: 35 mapType::iterator my_Iter; 36 my_Iter = mapStu1.find(3); 37 string str3 = my_Iter->second; 38 cout << str3 << endl << endl; 39 // 修改数据的两种方式: 40 // 方式1: 41 mapStu1[2] = "Ma"; 42 // 方式2: 43 my_Iter->second = "Yuan"; 44 print(mapStu1); 45 // size 函数 和 empty函数 46 cout << "size() :: " << mapStu1.size() << endl; 47 cout << "empty() :: " << mapStu1.empty() << endl; 48 mapStu1.clear(); 49 cout << "size() :: " << mapStu1.size() << endl; 50 cout << "empty() :: " << mapStu1.empty() << endl; 51 // 比较 ==、>=、<=、!= 52 mapType mapStu2; 53 cout << "mapStu1 == mapStu2 :: " << (mapStu1 == mapStu2) << endl; 54 cout << "mapStu1 >= mapStu2 :: " << (mapStu1 >= mapStu2) << endl; 55 cout << "mapStu1 <= mapStu2 :: " << (mapStu1 <= mapStu2) << endl; 56 cout << "mapStu1 != mapStu2 :: " << (mapStu1 != mapStu2) << endl << endl; 57 58 mapStu1.insert(map<int, string>::value_type(1, "Qin")); 59 mapStu1.insert(map<int, string>::value_type(2, "Sun")); 60 mapStu1.insert(map<int, string>::value_type(3, "Wang")); 61 mapStu1.insert(map<int, string>::value_type(4, "Qiang")); 62 mapStu1.insert(map<int, string>::value_type(5, "Huang")); 63 mapStu1.insert(map<int, string>::value_type(6, "Li")); 64 mapStu1.insert(map<int, string>::value_type(7, "Hou")); 65 mapStu1.insert(map<int, string>::value_type(8, "Lin")); 66 mapStu1.insert(map<int, string>::value_type(9, "Li")); 67 68 // 删除操作 69 cout << "删除前打印数据信息:" << endl; 70 print(mapStu1); 71 mapType::iterator iter; 72 // 第一种删除(代码1) 73 for (iter = mapStu1.begin(); iter != mapStu1.end();) 74 { 75 if (5 == iter->first) 76 { 77 iter = mapStu1.erase(iter); 78 } 79 else 80 { 81 ++iter; 82 } 83 } 84 85 // 第一种删除(代码2)(注意代码层面的差异) 86 for (iter = mapStu1.begin(); iter != mapStu1.end();) 87 { 88 if ("Li" == iter->second) 89 { 90 mapStu1.erase(iter++); 91 } 92 else 93 { 94 ++iter; 95 } 96 } 97 cout << "删除关键字5 以及 值“Li”后: " << endl; 98 print(mapStu1); 99 100 // 第一种删除(代码3)(注意代码层面的差异) 101 my_Iter = mapStu1.find(2); 102 mapStu1.erase(my_Iter); 103 cout << "删除关键字2后: " << endl; 104 print(mapStu1); 105 106 // 第二种删除(直接删除关键字) 107 int nResult = mapStu1.erase(3); // 如果删除了会返回1,否则返回0 108 cout << nResult << endl; 109 cout << "删除关键字3后: " << endl; 110 print(mapStu1); 111 112 // 第三种删除(用迭代器,成片的删除) 113 mapStu1.erase(++mapStu1.begin(), mapStu1.end()); 114 cout << "剩第一位,其它全部删除后: " << endl; 115 print(mapStu1); 116 117 system("pause"); 118 } 119 120 // run out: 121 /* 122 size: 3 123 key: 1 value: Qin 124 key: 2 value: Sun 125 key: 3 value: Wang 126 127 Sun 128 Wang 129 130 size: 3 131 key: 1 value: Qin 132 key: 2 value: Ma 133 key: 3 value: Yuan 134 135 size() :: 3 136 empty() :: 0 137 size() :: 0 138 empty() :: 1 139 mapStu1 == mapStu2 :: 1 140 mapStu1 >= mapStu2 :: 1 141 mapStu1 <= mapStu2 :: 1 142 mapStu1 != mapStu2 :: 0 143 144 删除前打印数据信息: 145 size: 9 146 key: 1 value: Qin 147 key: 2 value: Sun 148 key: 3 value: Wang 149 key: 4 value: Qiang 150 key: 5 value: Huang 151 key: 6 value: Li 152 key: 7 value: Hou 153 key: 8 value: Lin 154 key: 9 value: Li 155 156 删除关键字5 以及 值“Li”后: 157 size: 6 158 key: 1 value: Qin 159 key: 2 value: Sun 160 key: 3 value: Wang 161 key: 4 value: Qiang 162 key: 7 value: Hou 163 key: 8 value: Lin 164 165 删除关键字2后: 166 size: 5 167 key: 1 value: Qin 168 key: 3 value: Wang 169 key: 4 value: Qiang 170 key: 7 value: Hou 171 key: 8 value: Lin 172 173 1 174 删除关键字3后: 175 size: 4 176 key: 1 value: Qin 177 key: 4 value: Qiang 178 key: 7 value: Hou 179 key: 8 value: Lin 180 181 剩第一位,其它全部删除后: 182 size: 1 183 key: 1 value: Qin 184 185 请按任意键继续. . . 186 */
(5)map 容器排序问题
请看下面一段代码:
1 #include <map> 2 #include <cstring> 3 using namespace std; 4 5 typedef struct tagStudentInfo 6 { 7 int nID; 8 string strName; 9 } StudentInfo, *PStudentInfo; // 学生信息 10 11 void main() 12 { 13 // 用学生信息映射分数 14 map<StudentInfo, int> mapStudent; 15 StudentInfo studentInfo; 16 studentInfo.nID = 1; 17 studentInfo.strName = "student_one"; 18 mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); 19 studentInfo.nID = 2; 20 studentInfo.strName = "student_two"; 21 mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); 22 }
注意:以上程序编译无法通过!
由编译器错误提示分析:排序问题!STL中默认是采用小于号来排序的,当关键字是一个结构体时,涉及到排序就会出现问题。
因为它没有小于号操作,insert等函数在编译的时候过不去,下面给出两个方法解决这个问题:
1、解决方法1,重载运算符。
1 // 解决方法1 2 3 #include <map> 4 #include <cstring> 5 using namespace std; 6 7 typedef struct tagStudentInfo 8 { 9 int nID; 10 string strName; 11 12 bool operator < (tagStudentInfo const & _A)const 13 { 14 // 这个函数指定排序策略,按nID排序,如果nID相等的话,按strName排序。 15 if (nID < _A.nID) 16 return true; 17 if (nID == _A.nID) 18 return strName.compare(_A.strName) < 0; 19 20 return false; 21 } 22 } StudentInfo, *PStudentInfo; // 学生信息 23 24 void main() 25 { 26 // 用学生信息映射分数 27 map<StudentInfo, int> mapStudent; 28 StudentInfo studentInfo; 29 studentInfo.nID = 1; 30 studentInfo.strName = "student_one"; 31 mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); 32 studentInfo.nID = 2; 33 studentInfo.strName = "student_two"; 34 mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); 35 }
2、解决方法2,仿函数。
1 // 解决方法2 2 3 #include <map> 4 #include <cstring> 5 using namespace std; 6 7 typedef struct tagStudentInfo 8 { 9 int nID; 10 string strName; 11 } StudentInfo, *PStudentInfo; // 学生信息 12 13 class sort 14 { 15 public: 16 bool operator()(StudentInfo const & _A, StudentInfo const & _B) const 17 { 18 if (_A.nID < _B.nID) 19 return true; 20 if (_A.nID == _B.nID) 21 return _A.strName.compare(_B.strName) < 0; 22 23 return false; 24 } 25 }; 26 27 void main() 28 { 29 // 用学生信息映射分数 30 map<StudentInfo, int, sort> mapStudent; 31 StudentInfo studentInfo; 32 studentInfo.nID = 1; 33 studentInfo.strName = "student_one"; 34 mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); 35 studentInfo.nID = 2; 36 studentInfo.strName = "student_two"; 37 mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); 38 }
(6)待续...
【3】总结说明
(1)由于STL是一个统一的整体,map的很多用法都和STL中其它的东西结合在一起。
比如,在排序方面,这里默认用的是小于号,即less<>,如果要从大到小排序呢,这里涉及到的东西很多,在此无法一一加以说明。
(2)map容器内部有序,由红黑树保证,因此很多函数执行的时间复杂度都是log2N的,用map函数可以实现的功能,而STL Algorithm也可以完成该功能。
但是,建议用map自带函数,效率更高一些。
(3)map在空间上的特性。
由于map的每个数据对应红黑树上的一个节点,这个节点在不保存你的数据时,是占用16个字节:
一个父节点指针,左右两个孩子指针,还有一个枚举值(标示红黑的,相当于平衡二叉树中的平衡因子)。
Good Good Study, Day Day Up.
顺序 选择 循环 总结