1.关联容器类型
有序容器使用比较函数来比较关键字,从而将元素按顺序存储。默认情况下,比较操作是采用关键字类型的<运算符。无序容器使用关键字类型的==运算符和一个hash<key_type>类型的对象来组织元素。
<1>按关键字有序保存
map关联数组;保存关键字-值对set关键字即值,即只保存关键字的容器multimap关键字可重复出现的mapmultiset关键字可重复出现的set <2>无序集合
unordered_map 用哈希函数组织的mapunordered_set 用哈希函数组织的setunordered_multimp 哈希组织的map;关键字可以重复出现unordered_multiset 哈希组织的set;关键字可以重复出现 <3>map和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每个关键字关联的类型;只适用于mapvalue_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 6.map的下标操作
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或1c.lower_bound(k)返回一个迭代器,指向第一个关键字不小于k的元素c.upper_bound(k) 返回一个迭代器,指向第一个关键字大于k的元素c.equal_range(k) 返回一个迭代器pair,表示关键字等于k的元素的范围。若k不存在,pair的两个成员均等于c.end() <2>对map使用find代替下标操作
下标操作的副作用是有时我们只想知道一个元素是否在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; }