关联容器和顺序容器从本质上不同,关联容器的元素是按关键字来保存和访问的,顺序容器的元素是按照位置来顺序保存和访问的。
关联容器支持高效的关键字查找和访问。标准库提供了8个关键容器,主要的有map和set。
1、使用关联容器
关联容器不支持顺序容器的位置相关的操作,如push_back和push_front。关联容器的迭代器都是双向的。
map是关键字-值对的集合,例如,可以将人名作为关键字,电话号码作为值。我们就可以用名字作为下标来得到这个人的电话号码。
set就是关键字的简单集合,当只想知道一个值是否存在时,set最有用。
map<key,value> name;
//定义一个map对象
map<string,size_t> word_count;
//空容器
set<string> exclude={"the","but","and","or"};
//初始化set
map<string,string> authors={{"Joyce","James"},{"Austen","Jane"}};
//初始化map,有两个元素
初始化一个map时,必须提供关键字类型和值类型。map和set中关键字必须是唯一的,就是说一个关键字只能有一个元素相对应。不过容器multimap和multiset没有限制,它们都允许多个元素有相同的关键字。
vector<int> ivec;
for(vector<int>::size_type i=0;i!=10;++i)
{
ivec.push_back(i);
ivec.push_back(i);
//每个i保存两次
}
set<int> iset(ivec.begin(),ivec.end();
multiset<int> miset(ivec.cbegin(),ivec.cend());
cout<<ivec.size()<<endl; //输出20
cout<<iset.size()<<endl; //输出10
cout<<miset.size()<<endl; //输出20
2、关键字类型
关联容器对关键字类型有一些限制。对于有序容器——map、multimap、set和multiset,关键字类型必须定义元素比较的方法。默认情况下,用关键字类型的<运算符来比较两个关键字。
在实际中,如果一个类型定义了“正常的”<运算符,则该类型可以用作关键字类型。但是必须在定义关联容器类型时提供该操作的类型。比如说,有一个类Person,类中有比较操作compareAge,就是以人的年龄来比较。
bool compareAge(Person p1,Person p2)
{
return p1.age<p2.age;
}
那么为了使用自己定义的操作,在定义multiset时就必须提供两个类型:一个是关键字类型Person,另一个是比较操作的类型,应该是函数指针类型用于指向compareAge。
multiset<Person,decltype(compareAge)*> personTable(compareAge);
用compareAge来初始化personTable对象,这表示向personTable添加元素时,通过调用compareAge来为元素排序。在这里,我们使用decltype来指出自定义操作的类型。当用decltype来获得一个函数指针类型时,必须加上*来指出要使用一个给定函数类型的指针。
3、pair类型
pair是一个标准库类型,定义在头文件utility中。一个pair保存两个数据成员,它是用来生成特定类型的模板。当创建一个pair时,要提供两个类型名。
pair<string,strin> anon; //保存两个string
pair<string,size_t> word_count; //保存一个string和一个size_t
pair<string,vector<int>> line; //保存string和vector<int>
pair的默认构造函数会对数据成员进行值初始化。我们也可以自行提供初始化器,
pair<string,string> author{"James","Sam"};
pair有两个public数据成员:first和second。