概述
stl定义了另一种容器,名曰关联容器,关联容器和顺序容器的本质区别在于:关联容器通过键key来存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。关联容器的大部分行为与顺序容器相同,但其独特之处在于支持键的使用。
stl提供了两个基本的关联容器
1、map:容器中以键值的形式来组织数据。键key代表了数据在容器中的索引,而值则是表示所存储和读取的数据。
2、set:仅包含一个键,一般用于查询某个键是否存在。
举个例子:
字典是map的典型应用,字典中的字就是键,而字对应的内容解释就是值。
在某些文字处理中,set用作关键字的集合,程序决定这些关键字是否屏蔽。
set和map所包含的元素都具有不同的键,换句话说,一个相同的键不能在容器内出现两次(一个键无法对应多个值)。为了解决这个问题,标准库引入了multimap和multiset类型,这两种容器允许多个元素拥有相同的键。
举个例子:
在电话本的应用中,一个人名(键)可能对应多个号码(值),这时选用multimap较为合适。
pair类型
在讨论关联容器前,必须先引入一个与之关系密切的stl类型,pair类型。
pair类型是单个的键值对,说明白点,map中的单个元素就是一个pair类型元素,通过map迭代器进行解引用,得到的就是pair类型对象。
pair定义在utility头文件中。
pair类型提供的操作有:
1、pair<T1,T2> p1:创建一个空的pair对象,它的两个元素类型分别为T1,T2,采用值初始化(如string则初始化为"").
2、pair<T1,T2> p1(v1,v2):创建一个pair对象,它的两个元素类型分别为T1,T2,其中第一个成员初始化为v1,第二个成员初始化为v2.
3、make_pair(v1,v2):以v1和v2的值创建一个新的pair对象,起元素类型分别为v1和v2的类型.
4、p1<p2:两个pair之间的小于判断。采用字典次序比较,先比较p1.first和p2.first,如相等,则比较p1.second和p2.second.
5、p1==p2:如果两个pair对象的first和second元素依次相等,则返回真。该运算使用其元素的==运算(也就是元素类型必须提供==操作).
6、p.first:返回p中第一个的数据成员。
7、p.second:返回p中第二个数据成员。
技巧:pair类型的使用比较繁琐,因此,如果需要定义多个相同的pair类型,可以使用以下形式
typedef pair<string,string> name;
name shen("haha","hehe");
name wang("hoho","xixi");
map容器
在使用map前,必须包含map的头文件。
在定义map的时候,必须指明map的键值类型。
如:map<string,string> phone_book;//键为string类型,值为string类型
构造函数:
1、map<k,v> m:创建一个名为m的空map,键值类型分别为k和v。
2、map<k,v> m(m2):创建m2的副本m,m与m2必须有相同的键类型和值类型。
3、map<k,v> m(b,e):创建map类型的对象m,存储迭代器b和e标记范围内所有元素的副本(左闭合区间),元素类型必须能转换为pair<const k,v>。
注意:使用关联容器时,键的类型必须要有<操作符(比较操作符中的小于)。因为在向关联容器中增加元素时,是按照严格弱排序来排列的,即小的在大的前面,所以要实现这种排序,必须定义<操作符。
定义的类型:
map<k,v>::key_type:在map容器中,用作索引的键的类型。
map<k,v>::mapped_type:在map容器中,键所关联的值的类型。
map<k,v>::value_type:map容器中一个元素的类型,实际是一个pair类型,它的first是 map<k,v>::key_type类型,second是map<k,v>::mapped_type类型。
注意:对map迭代器进行解引用时,得到的是一个pair对象。那么,完全可以对map迭代器做->操作,这样比较简洁,看下面的例子:
map<int,int> ii_map;
...//插入元素
map<int,int>::iterator ii_iter=ii_map.begin();
cout <<ii_iter->first;
cout <<(*ii_iter).first;
map的操作
添加元素:
最常规的方法就是和顺序容器一样,使用map::insert成员函数插入元素。有以下三个版本:
1、m.insert(e):e是一个value_type类型(pair)。如果e.first不在m中,则插入一个值为e.second的新元素。反之,则保持m不变。
注意:该函数返回一个pair类型对象,这个对象的first是指向键为e.first的元素的map迭代器,second是一个bool类型的对象,表示是否插入了该元素。
2、m.insert(beg,end):beg和end是标志着元素范围的迭代器(左闭合区间)。迭代器指向的元素,必须为value_type类型。对于范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m中。返回void。
3、m.insert(iter,e):e是待插入的元素,类型必须为value_type(pair)。如果e.first不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置。返回一个迭代器,指向键为e.first的元素。
除了以上三种成员函数,还可以使用下标来实现添加元素。考虑以下的例子:
map<string,int> si_map;
si_map["haha"]=1;
以上示例执行了这些操作:
1、在si_map中搜索键为haha的元素,没找到。
2、将一个新的键值对插入si_map中,其中键位const string类型对象,保存了haha.值为int的初始化值,为0。
3、读取新插入的元素,并将它的值赋为1。
4、如果si_map中已经有haha这个键了,则将haha对应的值设置为1。
可见,map的下标即是元素的键。使用下标进行赋值时,如map中不存在给定的键,则添加这个键值。
查询操作
提供两个函数
1、m.count(k):返回m中键为k的元素出现的次数(对于map来说,只可能是0或1)
2、m.find(k):搜索m中键为k的元素,如搜索到,则返回指向这个元素的迭代器。否则,返回超出末端的迭代器。
删除元素
1、m.erase(k):删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数。(对于map来说,只可能是0或者1)
2、m.erase(p):从m中删除迭代器p所指向的值。p必须指向m中确实存在的元素,当然不能等于m.end()。返回void。
3、m.erase(b,e):从m中删除一段范围内的元素(左闭合区间)。b和e必须标记m中的一段有效范围。b和e要么相等(删除范围为空),要么b所指的元素必须在e所指的元素之前。返回void。