C++的容器类型可以分为顺序容器和关联容器两大类。顺序容器的知识可以参看我上篇的随笔《C++顺序容器知识总结》。关联容器支持通过键值来高效的查找和读取元素,这是它和顺序容器最大的区别。两种基本的关联容器类型是map和set。map的元素以键-值对的形式组织:键用作元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效的支持关于某个键是否存在的查询。下表是关联容器的类型:

map                      关联数组;元素通过键来存储和读取
set 大小可变的集合,支持通过键实现快速读取
multimap 支持同一个键多次出现的map类型
multiset 支持同一个键多次出现的set类型

一.pair类型

  在开始介绍关联容器之前,我们需要了解一种与之相关的标准库类型——pair类型,该类型定义在头文件utilty中。下表是pair类型提供的操作。

pair<T1,T2>    p1;                     创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化
pair<T1,T2> p1(v1,v2); 创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v2,second成员初始化为v2。
make_pair(v1,v2) 以v1,v2值创建一个新的pair对象,其元素类型分别是v1,v2类型
p1<p2 两个pair对象之间的小于运算,遵循字典顺序
p1==p2 如果两个pair对象的first和second值依次相等,则它们相等
p.first 返回p中名为first的数据成员
p.second 返回p中名为second的数据成员

  可以看到,和容器一样,pair也是一种模板类型。它的数据成员是公有的,分别命名为first和second,只需点操作就可以访问其成员。其定义初始化的操作也很简单,除了构造函数外,pair还提供了一个make_pair函数来创建pair对象,并赋值给已存在的pair对象。

  

pair<string,string>    next_auth;
string first,last;
while(cin>>first>>last)
next_auth=make_pair(first,last);
//上面的赋值操作等效于下面这条语句
next_auth=pair<string,string>(first,last);

二.map类型

  map是键-值对的集合。map类型可以理解为关联数组:可以使用键作为下标来获取一个值,正如内置数组类型一样。map和set等关联容器共享大部分顺序容器的操作。关联容器不提供front、push_front、pop_front、back、push_back和pop_back操作。

1.map对象的定义

  在使用map对象之前,需要在头文件中包含map头。其定义示例如下:

#include<map>
map<string,int> word_count;

  此外,map还共有3种构造函数用于定义和初始化。

map<k,v>    m;                 创建一个名为m的空map对象,其键和值类型分别为k和v类型
map<k,v> m(m2); 创建一个m2的副本m,m和m2必须要有相同的键和值类型
map<k,v> m(b,e); 创建map类型的对象m,存储迭代器b和e标记范围内所有元素的副本。元素的类型必须能转换位pair<const k,v>

  

2.map定义的类型

  由于map对象的元素是键-值对,即每个元素包含两个部分:键以及由键关联的值。vaule_type是存储元素的键以及值得pair类型,而且键位const。下表为map类定义的类型。

map<K,V>::key_type               在map容器中,用作索引的键的类型
map<K,V>::mapped_type 在map容器中,键所关联的值的类型
map<K,V>::value_type 一个pair类型。它的first元素具有const map<K,V>::key_type 类型,而second元素具有map<K,V>::mapped_type类型

  注意对map迭代器进行解引用将产生的是pair类型的对象,它的first成员存放的是键,为const,second成员存放的是值。

3.map中添加元素

  给map添加元素有两种方式:一是使用insert成员实现。二是先用下标获取元素,让然后给获取的元素赋值。

  map使用下标和vector类似,返回的都是下标关联的值,但是map的下标是键而不是递增的数字。下面的程序很好的说明了这个特点。

map<string,int>    word_count;
word_count["Anna"]=;

  首先在word_count中查找键为Anna的元素,没有找到。接着将一个新的键-值对插入到word_count容器中,键为Anna,值初始化为0;最后会把值1赋值给键为Anna的元素。我们可以看到,用下标访问map中不存在的元素,会导致在map容器中添加一个新元素,它的键即为该下标值。map的下标运算和vector下标运算相同:返回键相关联的值。运用map容器的这些特点,可以使编程编的很简练。如下面记录每个单词出现次数的例子:

map<string,int>    word_count;
string word;
//统计word_count中某个单词出现的次数
while(cin>>word)
++word_count;

  map容器的insert使用的是pair类型的参数。如下表为map容器提供的insert操作。

  

m.insert(e)              e是一个用在m上的vaule_type类型的值。如果键e.first不在m中,则插入一个键为e.first值为e.seconde的元素。如果该键在m中已存在。则m保持不变。
该函数返回一个pair类型的对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入成功。
m.insert(beg,end) beg和end是标记元素范围的迭代器,其中的元素必须为m.value_type类型的键-值对。
对于该范围内的素有元素,如果它的键在m中不存在,则将该键及其关联的值插入m。返回void
m.insert(iter,e) e是一个用在vaule_type类型的值。如果键不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置。
返回一个迭代器,指向m中具有给定键的元素。

  如下:

//方法一
word_count.insert(map<string,int>::value_type("Anna",)); //方法二,使用make_pair
word_count.inser(make_pair("Anna",)); //方法三,使用typedef
typedef map<string,int>::value_type valType;
word_count.insert(valType("Anna",));

4.map中元素的查找与读取

  map中下标读取元素的缺点是当不存在该元素时会自动添加,有时这是我们不希望看到的。所以map提供了另外两个操作:count和find,用于检查某个键是否存在而不会插入该键。

m.count(k)               返回m中k出现次数
m.find(k) 如果m容器中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器

  count成员的返回值只能是0或1,因为map值允许一个键对应一个实例。如果返回值为非0,则可以用下标操作来获取该键所关联的值。

int occurs=;
if(word_count.count("foobar"))
occurs=word_count["foobar"];

  find操作凡湖指向元素的迭代器,如果元素不存在,则返回end迭代器。

int  occurs=;
map<string,int>::iterator it=word_count.find("foobar");
if(it!=word_count.end())
occurs=it->second;

5.map中删除元素

  从map容器中删除元素用erase操作,它有三种变化形式,如下:

m.erase(k)                删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数
m.srase(p) 从m中删除迭代器p指向的元素。p必须指向m中确实存在的元素,而且不能等于m.end()。返回void型
m.erase(b,e) 从m中删除一段范围内的元素,该范围由迭代器对b和e标记。b和e必须标记m中的一段有效范围:即b和e都必须指向m中的元素或最后元素的下一个位置
而且,b要么在e的钱main,要么和e相等。返回void

6.map对象的迭代遍历

  map和其他容器一样也提供begin和end运算。

map<string,int>::const_iterator   map_it=word_count.begin();

while(map_it!=word_count.end()){
cout<<map_it->first<<"occurs"
<<map_it->second<<"time"<<endl;
++map_it;
}

三.set类型

  set只是单纯的键的集合。当只想知道一个值是否存在时,使用set容器是最合适的。set容器支持大多数map的操作,包括构造函数、insert、count、find、erase操作。但是不包括下标操作,没有定义mapped_type类型。在set容器中value_type不是pair类型,而是与key_type相同的类型。与map一样,set容器中存储的键也是唯一的。

1.set的定义与使用

  使用set之前必须包含set头文件,set支持的操作基本与map提供的相同。

vector<int > ivec;
for(vector<int>::size_type i=;i!=;++i){
ivec.push_back(i);
ivec.push_back(i);
} //用ivec初始化set
set<int> iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl; //输出20
cout<<iset.size()<<end; //输出10

2.在set中添加元素

  

//方法一,直接插入
set<string> set1;
set1.insert("the"); //方法二,使用迭代器
set<string> set2;
set2.insert(ivec.begin(),ivec.end());

3.从set中获取元素

  set没有下标操作,为了通过键从set中获取元素,可使用find运算。如果仅是判断某个元素是否存在,也可使用count操作,返回值只能是1或0。

参考文献

C++ PRIMER》 中文版

C++关联容器知识总结的更多相关文章

  1. STL之关联容器---set, mutilset, map, mutilmap

    STL的容器分为序列容器和关联容器.它们所表达的数据结构各有不同: 序列容器:vector(变长数组), list(链表), queue(队列), heap(堆算法)等 关联容器:set/mutils ...

  2. 条目二十三《考虑用排序的vector替代关联容器》

    条目二十三<考虑用排序的vector替代关联容器> 在看到这个条目的标题的时候,说实话,我一下子是比较懵逼的.这个结论怎么和数据结构的时间复杂度不一致了? 一般来说,像map,set等关联 ...

  3. STL之关联容器

    关联容器包含map.set.multimap.multiset. 关联容器的特点是明显的,相对于顺序容器,有如下特点: 1.其内部是采用非线性的二叉树结构,具体的说是红黑树的结构原理实现的. 2.se ...

  4. STL_关联容器 VS C++ hashmap

    红黑树和哈希表区别: http://m.blog.csdn.net/article/details?id=52133283 关于STL中关联容器的几个问题: (1)为何map和set的插入删除效率比用 ...

  5. C++学习基础四——顺序容器和关联容器

    —顺序容器:vector,list,queue1.顺序容器的常见用法: #include <vector> #include <list> #include <queue ...

  6. C++ 关联容器

    <C++ Primer 4th>读书笔记 关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素. 关联容器(Ass ...

  7. C++ Primer : 第十一章 : 关联容器之关联容器的迭代器和操作

    关联容器的操作 除了和顺序容器定义的类型之外,关联容器还定义了一下几种类型: 关联容器额外的类型别名  key_type    此容器类型的关键字类型 mapped_type  每个关键字关联的类型, ...

  8. C++ Primer : 第十一章 : 关联容器之概述、有序关联容器关键字要求和pair类型

    标准库定义了两种主要的关联容器:map和set map中的元素时一些关键字-值(key-value)对,关键字起到索引的作用,值则表示与索引相关的数据.set中每个元素只包含一个关键字,可以完成高效的 ...

  9. 使用multimap创建重复键关联容器

    在“使用 <map> 库创建关联容器”一文中,我们讨论了标准库中的 map 关联容器.但那只是 map 容器的一部分.标准库还定义了一个 multimap 容器,它与 map 类似,所不同 ...

随机推荐

  1. eclipse生成【带有外部jar包】的java可执行jar包

    之前有写过一篇使用eclipse生成java可执行jar包,但是最近的一次使用中无论如何都不成功,当双击执行打成的jar时,弹出如下错误: could not find the main class: ...

  2. 数据库 事务的特性ACID

    数据库 事务的特性ACID 事务(Transaction)是并发控制的基本单位. 所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位.例如,银行转帐工作:从一个帐 ...

  3. Docker 小记 — Compose & Swarm

    前言 任何相对完整的应用服务都不可能是由单一的程序来完成支持,计划使用 Docker 来部署的服务更是如此.大型服务需要进行拆分,形成微服务集群方能增强其稳定性和可维护性.本篇随笔将对 Docker ...

  4. tar、scp、sftp、rsync简单使用

    tar -c 创建一个归档文件 -z 指定压缩格式为gzip -v 显示详细信息 -f 制定文件明 -j 指定压缩格式为bz2 -J 指定压缩格式为 xz -C 压缩.解压至某个目录 -x 自动识别压 ...

  5. C#图解教程 第十五章 接口

    接口 什么是接口 使用IComparable接口的示例 声明接口实现接口 简单接口示例 接口是引用类型接口和as运算符实现多个接口实现具有重复成员的接口多个接口的引用派生成员作为实现显式接口成员实现 ...

  6. java基础之二分法查找

    package p1; import java.util.*; public class Sortdob { public static void BubbleSort(int[] arr) {    ...

  7. 关于margin-top的一些特别问题

    当给子元素添加了margin-top的数值,浏览器解析的时候默认添加到父元素上解决的方法: 1 给父元素添加一个上边框border-top. 2 或者给子元素加个浮动. 3  给父元素添加overfl ...

  8. [Luogu4174][NOI2006]最大获益

    luogu sol 一周没摸键盘了回来刷刷水题练练手感 显然,最大化收益可以转化为最小化损失,从而建立最小割模型. 记\(tot=\sum_{i=1}^{m}C_i\),事先假设所有的获益都得到了,那 ...

  9. 【BZOJ1257】余数之和(数论分块,暴力)

    [BZOJ1257]余数之和(数论分块,暴力) 题解 Description 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + - + k mod n的 ...

  10. [HNOI2007]紧急疏散

    二分+网络流判定 首先处理出每个人和门间的距离 二分时间,连边时把每个门拆成mid个,一个人能在mid时间内到达,他也可以在这等一会儿,那么这mid个门之间连边 如果可以在x的时间内到达,那么x~mi ...