1.关联容器类型
有序容器使用比较函数来比较关键字,从而将元素按顺序存储。默认情况下,比较操作是采用关键字类型的<运算符。无序容器使用关键字类型的==运算符和一个hash<key_type>类型的对象来组织元素。
<1>按关键字有序保存
map | 关联数组;保存关键字-值对 |
set | 关键字即值,即只保存关键字的容器 |
multimap | 关键字可重复出现的map |
multiset | 关键字可重复出现的set |
unordered_map | 用哈希函数组织的map |
unordered_set | 用哈希函数组织的set |
unordered_multimp | 哈希组织的map;关键字可以重复出现 |
unordered_multiset | 哈希组织的set;关键字可以重复出现 |
int main()
{
map<string, size_t> word_count;
set<string> exclude = { "am","is","my"};
string word;
while (cin >> word)
if (exclude.find(word) == exclude.end())//只统计不在exclude中的单词
++word_count[word];//如果word还未在map中,下标运算符会创建一个新元素
for (auto w : word_count)
cout << w.first << " occurs " << w.second <<((w.second>1)?" times ":" time ")<< endl;
system("pause");
return 0;
}
2.pair类型
<1>一个pair保存两个数据成员。类似容器,pair是一个用来生成特定类型的模板。定义在头文件utility中。
pair<string, int> p1;
pair<string, string> p2{ "wang","kai" };
3.关联容器操作
<1>
key_type | 容器类型的关键字类型 |
mapped_type | 每个关键字关联的类型;只适用于map |
value_type | 对于map,为pair<const key_type,mapped_type> 对于set,与key_type相同 |
int main()
{
set<string>::value_type v1;//v1是一个string
map<string, int>::key_type v2;//v2是一个string
map<string, int>::mapped_type v3;//v3是一个int
map<string, int>::value_type v4;//v4是一个pair<const string,int>
system("pause");
return 0;
}
<2>关联容器迭代器
当解引用一个关联容器迭代器时,我们会得到一个类型为容器的value_type的值的引用。注意:不能改变关键字成员的值。
int main()
{
map<int, string> m{ {1,"wang"},{2,"li"},{3,"zhao"} };
auto map_it = m.begin();
map_it->first = 5;//错误。“map_it”: 不能给常量赋值
map_it->second = "yan";//正确
system("pause");
return 0;
}
set的迭代器是const的,所以可以用一个set迭代器来读取元素的值,但不能修改。
int main()
{
set<int> s = {1,2,3,4,5};
set<int>::iterator set_it = s.begin();
*set_it = 6;//错误。“set_it”: 不能给常量赋值
system("pause");
return 0;
}
4.向关联容器中添加元素
<1>要注意的是,map中元素的类型是pair。
int main()
{
map<string, int> word_count;
word_count.insert(make_pair("wang",1));
word_count.insert({ "yan",2 });
word_count.insert(pair<string, int>("rong", 3));
system("pause");
return 0;
}
<2>insert返回的值依赖于容器类型和参数。对于不包含关键字的容器,添加单一元素的insert和emplace版本返回一个pair。pair的first成员是一个迭代器,指向具有给定关键字的元素;second成员是一个bool值,指出元素是插入成功还是已经存在于容器中。如果关键字已经存在于容器中,则insert什么事情也不做,返回值的bool部分为false。如果关键字不存在,元素被插入到容器中,且bool值为true。
理解下面代码(C++ PrimerP385页):
int main()
{
string word;
map<string, size_t> word_count;
while (cin >> word)
{
auto ret = word_count.insert({ word,1 });
if (!ret.second)
++ret.first->second;
}
system("pause");
return 0;
}
<3>向multiset或multimap中添加元素时,insert总会插入一个元素。此时,insert操作返回一个指向新元素的迭代器,指向这个新插入的元素。
5.向关联容器中删除元素
c.erase(k) | 从c中删除每个关键字为k的元素。返回一个size_type值。指出删除元素的数量。 |
c.erase(p) | 从c中删除迭代器p指定的元素。p必须指向c中一个真实元素,不能等于c.end()。返回一个指向p之后元素的迭代器。若p指向c中的尾元素,则返回c.end() |
c.erase(b,e) | 删除迭代器对b和e所表示的范围中的元素。返回e |
map和unordered_map容器提供了下标运算符和一个对应的at函数。注意set类型不支持下标运算符,因为没有于关键字相关联的值。同时,也不能对一个multimap或一个unordered_multimap进行下标操作,因为这两个容器可能有多个值与一个关键字相对应。
map的下标运算与以前其它下标运算的不同之处是返回类型。一般来说,解引用一个迭代器返回的类型与下标运算符返回的类型是一样的。但在map中,当对map进行下标操作时,会得到一个value_type对象(值),但当解引用一个map迭代器时,会得到value_type对象(pair)。此外,若关键字还未在map中,下标运算符会添加一个新元素。
7.访问元素
<1>lower_bound或upper_bound不适用于无序容器。此外,下标和at操作只适应用于非const的map和unordered_map。
c.find(k) | 返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回尾后迭代器 |
c.count(k) | 返回关键字等于k的元素的数量。对于不允许重复关键字的容器,返回值永远是0或1 |
c.lower_bound(k) | 返回一个迭代器,指向第一个关键字不小于k的元素 |
c.upper_bound(k) | 返回一个迭代器,指向第一个关键字大于k的元素 |
c.equal_range(k) | 返回一个迭代器pair,表示关键字等于k的元素的范围。若k不存在,pair的两个成员均等于c.end() |
下标操作的副作用是有时我们只想知道一个元素是否在map中,但利用下标操作使得元素不存在时会自动添加。所以只查看时可以借助上表中的方法。
<3>应用举例
int main()
{
string search_item("yan rong");//要查找的作者名称
auto entries = authors.count(search_item);//作品数量
auto iter = autors.find(search_item);//作者的第一本书
while (entries)
{
cout << iter->second << endl;//打印找到的书名
++iter;//符合条件的下一本书
--entries;
}
system("pause");
return 0;
}
int main()
{
string search_item("yan rong");
for (auto pos = authors.equal_range(search_item); pos.first != pos.second; ++pos.first)//pos中保存的是迭代器,表示与关键字匹配的元素范围
cout << pos.first->second << endl;
system("pause");
return 0;
}