UPDATE(20190416):写完vector和set以后,发现很多内容所有引导到map上了……因而进行了必定的描述补充与更正。html
零、STL目录c++
一、容器之map算法
二、容器之vector小程序
三、容器之set数组
1、前言数据结构
鉴于最近很多次都要用到map我却老是出各类bug,因而决定写一篇总结来巩固一下。函数
这篇文章虽名为STL容器之map,但其实包含了整个STL及其容器的概念与用途,以及诸如vector, set等基本容器的许多常规操做,能够做为一篇STL容器的总领性文章。spa
2、什么是STLcode
全称Standard Template Library,中文名标准模板库,目的是标准化组件,属于C++语言的一部分,说白了就是算法的整合包,最经常使用的例子即是快速排序,在C中你只能老老实实地码出来,而C++中调用<algorithm>中的sort函数便可。htm
3、STL容器
STL分为六个部分,这里重点介绍其中的容器(containers)部分。STL容器本质是一些经常使用的数据结构的模板,简化操做。容器分为以下几种,并列出几种最经常使用的:
一、序列式容器(经常使用:vector/向量)
二、适配器容器(经常使用:stack/栈,queue/队列,priority_queue/优先队列)
三、关联式容器(经常使用:set/集合,map/映射)
今天,咱们重点介绍map,即映射。
4、map的用途
I miss the taste of the sweeter life...哦对不起串了。
从名字就很好理解做用了——映射,令一物与另外一物之间创建起一一映射的关系,以便得到将不方便查找的信息。
举个例子,一个很简单的问题,读入n个长度为m的字符串,再询问q次某某字符串是否在其中。初学者选择字符一一比对,O(nmq);这是有人说,聪明人看到字符串早就去Hash了,能够,but,为保证正确性,哈希值一样会很大,开一个数组去存怕是无内存上限。
那好,咱们将获得的哈希值编一个号,好比某巨大的数咱们将它视做1,另外一个巨大的数编成2,再把编号与值一一对应的关系给记录下来,用什么记录?
map:正是在下。
5、map的声明与功能
上面提了,map用途在于自动创建编号与值的对应。那么STL提供了哪些函数供咱们来捣鼓里面的东西呢?
函数清单:insert, begin, end, size, rbegin, rend, find, count, lower_bound, upper_bound, erase。
其实这些函数中大部分也是STL容器中通用的函数,下面会有详细的使用介绍,适用于但不只限于map。
一、构造
map <int, string> a;
简单明了,前者为键值(key),后者为值(value),此处为整形&字符串的映射,二者亦可为任何其余支持的类型。
二、插入数据
方法一(以pair形式):
a.insert(pair <int, string>(1, "Zhangsan")); a.insert(pair <int, string>(2, "Lisi")); a.insert(pair <int, string>(3, "Wangwu"));
方法二(以value_type形式):
a.insert(map <int, string> :: value_type(1, "Zhangsan"));
方法三(以数组形式):
a[1] = "Zhangsan";
须要注意的是,方法一二没法覆盖数据,而方法三能够,即若是键值为1的map已经被映射到“Zhangsan”,能够经过数组形式直接修改。
三、数据遍历
这里引入新概念——迭代器(iterator)。先声明:
map <int, string>::iterator it;
使用方法也很简易:
for (it = a.begin(); it != a.end(); it++) cout << it -> first << ' ' << it -> second << endl;
这个是前向迭代器,一样还有反向迭代器,以下:
map <int, string> :: reverse_iterator rit;
for (rit = a.rbegin(); rit != a.rend(); rit++) cout << rit -> first << ' ' << rit -> second << endl;
一样地,还有用数组的方式遍历:
int s = a.size(); for (int i = 1; i <= s; i++) cout << i << ' ' << a[i] << endl;
其中,size函数是用来获取map中有多少项数据。
注意点:在遍历时咱们用了begin()和end(),二者类型均为迭代器。咱们发现遍历起始点为begin(),当迭代器不等于end()时继续,这意味着begin()为开头标识,它包括了数据内容,即第一项数据;end()为结尾标识,但它是最后一项数据后面的一个独立的标识,自己并不表示任何数据。
四、查找数据
①判断是否出现用count函数
②判断出如今哪里用find函数
map <int, string> :: iterator itx; itx = map.find(1); int x = map.count(1); map <int, string> :: iterator ity; ity = map.find(4); int y = map.count(4);
count函数只返回0或1,如上述代码中,x = 1, y = 0;
find函数返回的是一个迭代器,如上述代码中,itx -> first = 1, itx -> second = "Zhangsan";
而若是没有该数据的话,则返回的是it = a.end()(末尾标识)。
五、上界下界
lower_bound()返回要查找关键字的下界,即值 >= 给定元素的第一个位置,upper_bound()返回上界,即值 > 给定元素的第一个位置。
1 map <int, int> a; 2 3 int main() { 4 a[1] = 1, a[2] = 2, a[3] = 3, a[4] = 4; 5 map <int, int> :: iterator it; 6 for (int i = 1; i <= 4; i++) { 7 it = a.lower_bound(i); 8 printf("%d ", it -> first); 9 } 10 for (int i = 1; i <= 4; i++) { 11 it = a.upper_bound(i); 12 printf("%d ", it -> first); 13 } 14 return 0; 15 }
输出结果为“1 2 3 4 2 3 4 4”,其中upper_bound(4)因为不存在,故it = a.end(),而为何it -> first输出4,这是个哲学问题,引用哲学家Cab的话说,“从结论上说访问end的first是会获得size,然而是undefined behavior(未定义行为)”。因此大可没必要纠结这东西了。
六、删除元素
这里介绍两种删除方法:单删除,区间删除。
单删除即直接删除一项,传入参数能够为键值,也能够为一个迭代器。
map <int, string> :: iterator it; a.erase(1); it = a.find(2); a.erase(it);
区间删除只能为迭代器。听上去美,可是毕竟这是map不是for,当你的数据并非美好的从1到n连续编号时,你只能拿它做clear的操做了,也就是:
a.erase(a.begin(), a.end());
从这里又可得知一点,erase两个参数也是左闭右开的关系,即包括前者不包括后者。
七、排序问题
map中的元素是自动按键值升序排序,不管是数仍是字符串。但若是键值为一个结构体,咱们须要重载小于符号。以下小程序中,咱们将囊括学号姓名两项数据的结构体做为键值,成绩做为值,而后须要以学号进行升序排序:
#include <bits/stdc++.h> using namespace std; #define MAXN 35 struct Stu { int id; string str; bool operator < (Stu const& x) const { return id < x.id; } }; map <Stu, int> a; int n, id, o; string str; int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> id >> str >> o; a.insert(pair <Stu, int> ((Stu) {id, str}, o)); } map <Stu, int> :: iterator it; for (it = a.begin(); it != a.end(); it++) cout << it -> first.id << ' ' << it -> first.str << ' ' << it -> second << endl; return 0; }
6、小结
STL广泛有一个前闭后开的特性,这里有两处均能体现:一处是关于begin()和end()的定义,一处是erase()的区间删除方式,之后应该还会接触到更多。
平时STL容器用的不是太多,也就queue, priority_queue, map较为经常使用。算法却是常常用(algorithm库),之后有机会再慢慢总结STL的其余部分。