C++的容器类型能够分为顺序容器和关联容器两大类。顺序容器的知识能够参看我上篇的随笔《C++顺序容器知识总结》。关联容器支持经过键值来高效的查找和读取元素,这是它和顺序容器最大的区别。两种基本的关联容器类型是map和set。map的元素以键-值对的形式组织:键用做元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效的支持关于某个键是否存在的查询。下表是关联容器的类型:html
map 关联数组;元素经过键来存储和读取 set 大小可变的集合,支持经过键实现快速读取 multimap 支持同一个键屡次出现的map类型 multiset 支持同一个键屡次出现的set类型
在开始介绍关联容器以前,咱们须要了解一种与之相关的标准库类型——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和set等关联容器共享大部分顺序容器的操做。关联容器不提供front、push_front、pop_front、back、push_back和pop_back操做。app
在使用map对象以前,须要在头文件中包含map头。其定义示例以下:函数
#include<map> map<string,int> word_count;
此外,map还共有3种构造函数用于定义和初始化。spa
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>
因为map对象的元素是键-值对,即每一个元素包含两个部分:键以及由键关联的值。vaule_type是存储元素的键以及值得pair类型,并且键位const。下表为map类定义的类型。code
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成员存放的是值。htm
给map添加元素有两种方式:一是使用insert成员实现。二是先用下标获取元素,让而后给获取的元素赋值。对象
map使用下标和vector相似,返回的都是下标关联的值,可是map的下标是键而不是递增的数字。下面的程序很好的说明了这个特色。blog
map<string,int> word_count; word_count["Anna"]=1;
首先在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",1)); //方法二,使用make_pair word_count.inser(make_pair("Anna",1)); //方法三,使用typedef typedef map<string,int>::value_type valType; word_count.insert(valType("Anna",1));
map中下标读取元素的缺点是当不存在该元素时会自动添加,有时这是咱们不但愿看到的。因此map提供了另外两个操做:count和find,用于检查某个键是否存在而不会插入该键。
m.count(k) 返回m中k出现次数
m.find(k) 若是m容器中存在按k索引的元素,则返回指向该元素的迭代器。若是不存在,则返回超出末端迭代器
count成员的返回值只能是0或1,由于map值容许一个键对应一个实例。若是返回值为非0,则能够用下标操做来获取该键所关联的值。
int occurs=0; if(word_count.count("foobar")) occurs=word_count["foobar"];
find操做凡湖指向元素的迭代器,若是元素不存在,则返回end迭代器。
int occurs=0; map<string,int>::iterator it=word_count.find("foobar"); if(it!=word_count.end()) occurs=it->second;
从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
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容器支持大多数map的操做,包括构造函数、insert、count、find、erase操做。可是不包括下标操做,没有定义mapped_type类型。在set容器中value_type不是pair类型,而是与key_type相同的类型。与map同样,set容器中存储的键也是惟一的。
使用set以前必须包含set头文件,set支持的操做基本与map提供的相同。
vector<int > ivec; for(vector<int>::size_type i=0;i!=10;++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
//方法一,直接插入 set<string> set1; set1.insert("the"); //方法二,使用迭代器 set<string> set2; set2.insert(ivec.begin(),ivec.end());
set没有下标操做,为了经过键从set中获取元素,可以使用find运算。若是仅是判断某个元素是否存在,也可以使用count操做,返回值只能是1或0。
参考文献
《C++ PRIMER》 中文版