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.

顺序  选择  循环  总结

posted @ 2017-02-21 23:53  kaizen  阅读(...)  评论(...编辑  收藏