11关联容器
关联容器
两个主要的关联容器是map和set.
map中的元素是一些key-value对。
set中每个元素只包含一个关键字。
三个维度划分8个关联容器:
-
或者是一个set,或者是一个map
-
或者要求不重复关键字,或者要求允许重复关键字
-
按顺序保存,无序保存
11.1 使用关联容器
map类型常称为关联数组(associative array)
set就是关键字的简单集合。 当只是想知道一个值是否存在时,set是最有用的。
使用map举例:
map<string,size_t> word_count; // string word; while(cin >> word) ++word_count[word]; //提取word的计数器并+
类似顺序容器,关联容器也是模板。为定义一个map,我们必须指定关键字和值的类型。
set中的元素是const
map中的元素是pair,其第一个成员是const的。
-
map:map中的元素是关键字-值(key-value)对。关键字起到索引作用,值则表示与索引相关联的数据。
-
set:set中每个元素只包含一个关键字,set支持高效的关键字查询操作-检查一个给定关键字是否存在set中。
允许重复的关键字的容器名字中都有multi。 无序保存的容器都以单词unordered开头。 无序容器采用哈希函数来组织非、元素。
- map和multimap定义在头文件map中。
- set和multiset定义在头文件set中。
- 无序容器定义在unordered_map中和unordered_set中。
map是键值相互对应的,称为关联数组。名字-电话组合。可以使用一个人的名字来作为下标获取此人的电话号码。 set是关键字的简单集合。一个企业中开空头支票的人。
关键字类型
对于有序容器-map/multimap/set/multiset/,关键字类型必须定义元素比较的方法。
默认情况下,标准库使用关键字类型的< 运算符来比较两个关键字。
map<vector<int>::iterator,int>m1;//有效 vector迭代器支持比较操作
map<list<int>::iteratro,int>m2;//无效、list的元素不是连续存储,迭代器不支持比较操作。
在集合类型中,关键字类型就是元素类型;在映射类型中,关键字类型就是元素的第一部分的类型。
用来组织一个容器中元素的操作的类型也是该容器类型的一部分,为了使用自定义的类型,必须在定义关联容器时提供此操作的类型。
bool compareIsbn(const Sales_data &lhs,const Sales_data &rhs){
return lhs.isbn() < rhs.isbn();
}; //此函数在Sales_data对象的ISBN成员上定义了一个严格弱序。
//用尖括号指出要定义哪种类型,自定义的操作类型必须在尖括号中紧跟着元素类型指出。
multiset<Sales_data,decltype(compareIsbn)*>
bookstore(compareIsbn);
// 用compareIsbn来初始化bookstore对象,这表示我们向bookstore中添加元素时,通过调用compareIsbn来为这些元素排序。
在定义multiset时我们必须提供两个类型:关键字类型Sales_data以及比较操作类型——应该是一种函数指针类型。我们使用decltype来指出自定义操作的类型。
当使用decltype来获得一个函数指针类型时,必须加上一个*来指出我们要使用的一个给定函数类型的指针。
关联容器操作
- key_type : 容器类型的关键字类型
- mapped_type: 只要map才定义 每个关键字关联的类型
- value_type: 对于set,与key_type相同。对于map,为pair<const key_value,mapped_value>
关联容器迭代器
auto map_it = word_count.begin(); *map_it指向一个pair<const string,size_t>对象的引用
cout << map_it->first;
cout << map_ir->second;
map_it->first = "new key" //错误 因为关键字是const的
map_it->second++; //正确 我们可以通过迭代器改变元素的值。
set<int>::iterator set_it =iset.begin() //关联容器迭代器 均只允许访问元素,而不允许修改元素的值。
关联容器添加元素
由于set和map包含不重复的关键字,所以插入一个已存在的元素对容器没有任何影响。 set容器添加元素
insert有两个版本:接受一对迭代器或是一个初始化列表。
set2.insert(ivec.cbegin(),ivec.cend());
set2.insert({12,1,23,4});
map容器添加元素
插入的元素类型必须是pair
map<string,size_t> word_count;
word_count.insert({word,1});
word_count.insert(make_pair(word,1));
word_count.insert(pair<string,size_t>(word,1));
word_count.insert(map<string,size_t>::value_type{word,1});
insert返回值
对于不包含重复关键字的迭代器,添加单一元素的insert和emplace版本返回一个pair.
map<string,vector<int>>;
类型的容器返回类型是 pair<map<string,vector<int>>::iterator,bool>;
pair的first的成员是一个迭代器,指向具有给定关键字的元素。
second元素是一个bool值,如果容器中已经存在,second元素为false,如果不在,则插入成功,返回true.
auto ret = word_count.insert({word,1});
if(!ret.second)
++ret.first->second;
//ret是insert的返回值,是一个pair.
ret.first:是pair的第一个成员,是一个map迭代器,指向具有给定关键字的元素。
ret.first->:解引用此迭代器,提取map的元素,元素也是一个pair.
ret.first->second:map中元素的值部分。
++ret.first->second:递增值。
向mulitmap或multiset添加元素
作者和他写的书籍。
对于允许重复的容器,接受单个元素插入,返回指向新元素的迭代器。
families.insert({family,child});
关联容器删除元素
- 顺序容器的erase(见erase目录)操作。
erase(key_type)
:返回实际删除元素的数量。不重复容器:返回0或1.0代表容器中没有该元素。
map的下标操作
- 只适用于map和unordered_map
- 适用不在容器内的关键字,会添加一个具有该关键字的map。
- 返回mapped_type对象,若对map迭代器解引用,则得到value_type对象。