STL之Map.docx

上传人:b****4 文档编号:4902466 上传时间:2022-12-11 格式:DOCX 页数:21 大小:48.25KB
下载 相关 举报
STL之Map.docx_第1页
第1页 / 共21页
STL之Map.docx_第2页
第2页 / 共21页
STL之Map.docx_第3页
第3页 / 共21页
STL之Map.docx_第4页
第4页 / 共21页
STL之Map.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

STL之Map.docx

《STL之Map.docx》由会员分享,可在线阅读,更多相关《STL之Map.docx(21页珍藏版)》请在冰豆网上搜索。

STL之Map.docx

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

mapclientMap;

这样我们定义了一个clientMap,如果我们要定义多个这样的map,需要多次写map变量名。

为了避免这样情况,我们通常为map定义个别名,如:

1

2

typedef mapclientEdp;

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   value_type;

 

    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   reverse_iterator;

    typedef    std:

:

reverse_iterator   const_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

mapclientMap;

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 mapclientEdp;

    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:

"<first<

        cout<<"scanRate:

"<second.scanRate<

        cout<<"socketAddr:

"<second.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 struct std:

:

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的定义可以在中找到,pair提供了一个方法方便创建键值对:

1

2

3

4

5

template pair

    std:

:

make_pair(const T1&t1,const T2&t2)

{

    return pair(t1,t2);

}

上面的例子中我们就用到了这个方法来创建(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());

    templatemap(Infirst,Inlast,

        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)

    pairinsert(const value_type&val);

    iteratorinsert(iteratorpos,const value_type&val);

    templatevoid insert(Infirst,Inlast);

 

    //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 mapclientEdp;

    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,如果插入成功bool值为TRUE,iterator指向插入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

#include

#include

#include

using namespace std;

 

typedef    int    clientId;

typedef struct{

    int scanRate;

    stringsocketAddr;

}clientInfo;

 

int main(int argc,char**argv)

{

    typedef mapclientEdp;

    typedef map:

:

const_itera

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1