STL之Map.docx
- 文档编号:4902466
- 上传时间:2022-12-11
- 格式:DOCX
- 页数:21
- 大小:48.25KB
STL之Map.docx
《STL之Map.docx》由会员分享,可在线阅读,更多相关《STL之Map.docx(21页珍藏版)》请在冰豆网上搜索。
STL之Map
STL之Map
概述
Map是标准关联式容器(associative container)之一,一个map是一个键值对序列,即(key,value)对。
它提供基于key的快速检索能力,在一个map中key值是唯一的。
map提供双向迭代器,即有从前往后的(iterator),也有从后往前的(reverse_iterator)。
map要求能对key进行<操作,且保持按key值递增有序,因此map上的迭代器也是递增有序的。
如果对于元素并不需要保持有序,可以使用hash_map。
map中key值是唯一的,如果马匹中已存在一个键值对(昵称,密码):
("skynet",407574364),而我们还想插入一个键值对("skynet",472687789)则会报错(不是报错,准确的说是,返回插入不成功!
)。
而我们又的确想这样做,即一个键对应多个值,幸运的是multimap可是实现这个功能。
下面我们用实例来深入介绍map、multimap,主要内容如下:
∙1、例子引入
∙2、map中的类型定义
∙3、map中的迭代器和键值对
∙4、map中的构造函数与析构函数
∙5、map中的操作方法
∙6、再议map的插入操作
∙7、[]不仅插入
∙8、multimap
∙9、总结
1、例子引入
有一个服务器manager维护着接入服务器的client信息,包括clinetId、scanRate、socketAddr等等。
我们定义一个结构体保存scanRate、socketAddr信息。
如下:
1
2
3
4
5
typedef int clientId;
typedef struct{
int scanRate;
stringsocketAddr;
}clientInfo;
我们用map保存这些信息:
clientId为键key,clientInfo为值。
这样我们可以通过clientId快速检索到client的相关信息,我们可以这样定义:
1
map
这样我们定义了一个clientMap,如果我们要定义多个这样的map,需要多次写map
为了避免这样情况,我们通常为map
1
2
typedef map
clientEdpclientMap;
之后我们就可以像定义clientMap一样定义map
如果我们需要修改map的定义,只需要在一处修改即可,避免修改不彻底造成的不一致现象。
我们这就完成了需要的map的定义,如果不定义或没有在它上面的操作的话,就像定义类而没有方法一样,意义不大或毫无意义。
幸运的是,STL提供了这些常用操作:
排序(注:
map是不能也不要排序的,因为map本身已经排好序了)、打印、提取子部分、移除元素、添加元素、查找对象,就像数据库的增删改查操作!
现在我们详细介绍这些操作,并逐步引入hash_map、multimap。
2、map中的类型定义
关联数组(associativearray)是最有用的用户定义类型之一,经常内置在语言中用于文本处理等。
一个关联数组通常也称为map,有时也称字典(dictionary),保存一对值。
第一个值称为key、第二个称为映射值mapped-value。
标准map是定义在std命名空间中的一个模板,并表示为
它首先定义了一组标准类型名字:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template
class A=allocator
class std:
:
map
{
public:
//types
typedef Key key_type;
typedef T mapped_type;
typedef pair
typedef Cmp key_compare;
typedef A allocator_type;
typedef typename A:
:
reference reference;
typedef typename A:
:
const_reference const_reference;
typedef implementation_define1 iterator;
typedef implementation_define2 const_iterator;
typedef typename A:
:
size_type size_type;
typedef typename A:
:
difference_type difference_type;
typedef std:
:
reverse_iterator
typedef std:
:
reverse_iterator
//...
}
注意:
map的value_type是一个(key,value)对,映射值的被认为是mapped_type。
因此,一个map是一个pair
从constKey可以看出,map中键key是不可修改的。
不得不提的是map定义中Cmp和A都是可选项。
Cmp是定义在元素之间的比较方法,默认是<操作;A即allocator用来分配和释放map总键值对所需使用的内存,没有指定的话即默认使用的是STL提供的,也可以自定义allocator来管理内存的使用。
多数情况,我们不指定这两个选项而使用默认值,这样我们定义map就像下面这样:
1
map
Cmp和A都缺省。
通常,实际的迭代器是实现定义的,因为map很像使用了树的形式,这些迭代器通常提供树遍历的某种形式。
逆向迭代器是使用标准的reverse_iterator模板构造的。
3、map中的迭代器和键值对
map提供惯常的返回迭代器的一组函数,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template
class A=allocator
class std:
:
map
{
public:
//...
//iterators
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
//...
}
map上的迭代器是pair
例如,我们可能需要打印出所有的客户端信息,像下面的程序这样。
为了实现这个,我们首先向《例子引入》中定义的clientEdp中插入数据,然后打印出来:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include
#include
#include
using namespace std;
typedef int clientId;
typedef struct{
int scanRate;
stringsocketAddr;
}clientInfo;
int main(int argc,char**argv)
{
typedef map
typedef map
:
const_iteratoriterator;
clientEdpclients;
clientInfoclient[100];
char str[10];
stringstrAddr("socketaddrclient");
for(int i=0;i<100;i++)
{
client[i].scanRate=i+1;
//convertinttochar*
itoa(i+1,str,10);
//concatenatestrAddrandstr
client[i].socketAddr=strAddr+str;
cout< clients.insert( make_pair(i+1,client[i])); } delete str; for(iteratori=clients.begin();i! =clients.end();i++) { cout<<"clientId: "< cout<<"scanRate: "< cout<<"socketAddr: "< cout< } } 一个map迭代器以key升序方式表示元素,因此客户端信息以cliendId升序的方式输出。 运行结果可以证明这一点,运行结果如下所示: 图1、程序运行结果 我们以first引用键值对的key,以second引用mappedvalue,且不用管key和mappedvalue是什么类型。 其实pair在std的模板中是这样定义的: 1 2 3 4 5 6 7 8 9 10 11 12 template : pair{ typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; pair(): first(T1()),second(T2()){} pair(const T1&x,const T2&y): first(x),second(y){} template pair(const pair&p): first(p.first),second(p.second){} } 即map中,key是键值对的第一个元素且mappedvalue是第二个元素。 pair的定义可以在 1 2 3 4 5 template std: : make_pair(const T1&t1,const T2&t2) { return pair } 上面的例子中我们就用到了这个方法来创建(clientId,clientInfo)对,并作为Insert()方法的参数。 每个pair默认初始化每个元素的值为对应类型的默认值。 4、map中的构造函数与析构函数 map类惯常提供了构造函数和析构函数,如下所示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template class A=allocator class std: : map { //... //construct/copy/destroy explicit map(const Cmp&=Cmp(),const A&=A()); template const Com&=Cmp(),const A&=A()); map(const map&); ~map(); map&operator=(const map&); //... } 复制一个容器意味着为它的每个元素分配空间,并拷贝每个元素值。 这样做是性能开销是很大的,应该仅当需要的时候才这样做。 因此,map传的是引用。 5、map中的操作方法 前面我们已经说过,如果map中仅定义了一些key、mappedvalue类型的信息而没有操作方法,就如定义个仅有字段的类意义不大甚至毫无意义。 由此可见map中定义操作方法非常重要! 前面的例子我们就用到了不少方法,如返回迭代器的方法begin()、end(),键值对插入方法insert()。 下面我们对map中的操作方法做个全面的介绍: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 template class A=allocator class std: : map { //... //mapoperations //findelementwithkeyk iteratorfind(const key_type&k); const_iteratorfind(const key_type&k)const; //findnumberofelementswithkeyk size_typecount()const; //findfirstelementwithkeyk iteratorlower_bound(const key_type&k); const_iteratorlower_bound(const key_type&k)const; //findfirstelementwithkeygreaterthank iteratorupper_bound(const key_type&k); const_iteratorupper_bound(const key_type&k)const; //insertpair(key,value) pair iteratorinsert(iteratorpos,const value_type&val); template //eraseelement void erase(iteratorpos); size_typeerase(const key_type&k); void erase(iteratorfirst,iteratorlast); void clear(); //numberoselements size_typesize()const; //sizeoflargestpossiblemap size_typemax_size()const; bool empty()const{return size()==0;} void swap(map&); //... } 上面这些方法基本都能顾名思义(PS.由此可见,命名有多重要,我们平时要养成好的命名习惯,当然注释也必不可少! )。 虽然已经非常清楚了了,但我还是想讲解一下以消除不惜要的误解和更好地应用这些方法。 ∙find(k)方法简单地返回键值为k的元素的迭代器;如果没有元素的键值为k,则返回map的end()迭代器。 由于map是按键key升序排列,所有查找的复杂度只有O(logN)。 因此,我们通常会这样用这个方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include #include #include using namespace std; typedef int clientId; typedef struct{ int scanRate; stringsocketAddr; }clientInfo; int main(int argc,char**argv) { typedef map typedef map : const_iteratoriterator; clientEdpclients; clientInfoclient[100]; char*str=new char[10]; stringstrAddr("socketaddrclient"); for(int i=0;i<100;i++) { client[i].scanRate=i+1; //convertinttochar* itoa(i+1,str,10); //concatenatestrAddrandstr client[i].socketAddr=strAddr+str; clients.insert( make_pair(i+1,client[i])); } delete str; #ff0000;"> #ff0000;">clientIdid=10; iteratori=clients.find(id); if(i! =clients.end()){ cout<<"clientId: "< <<"existsinclients"< } else{ cout<<"clientId: "< <<"doesn'texistinclients"< } } ∙insert()方法试图将一个(Key,T)键值对加入map。 因为键时唯一的,所以仅当map中不存在键值为k的键值对时插入才成功。 该方法的返回值为pair 如下代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include #include #include using namespace std; typedef int clientId; typedef struct{ int scanRate; stringsocketAddr; }clientInfo; int main(int argc,char**argv) { typedef map typedef map : const_itera
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- STL Map