C++primer第五版第11章笔记
关联容器
关联容器的元素是按照关键字来访问的,大体上分为map与set存储,map可以存key和value,set只能存key,我们添加multi将支持可重复的元素,添加unordered_支持无序。
11.1使用关联容器
map是一对关键字集合,保存key和value,我们可以通过key来存储相关的value,又称为key到value的映射。set只能保存一个关键字,我们可以在剔除某些数据时采用set来进行快速查找。
set<int>num{1};
num.find(1)==num.end();(find返回一个迭代器,若查找成功返回元素所在位置)
isalpha(m);(判断m是否是字母,是返回1)
tolower(m);(将字母转化为小写并返回)
11.2关联容器概述
关联容器支持一般普通容器操作,但由于关联容器靠关键字存储,所以关于一般容器一些位置操作不支持,如push_back等,同时,关联容器还支持一些普通容器不支持的操作。
11.2.1定义关联容器
我们可以使用{}形式来初始化关联容器,使用multimap或multiset可以存多个键值相同的元素。
11.2.2关键字类型的要求
如果关联容器是有序的,我们想往关联容器放置元素,关键字类型必须是定义了严格若序的,如果自定义类型可能需要定义比较函数。
struct ISBN{
int a;
string b;
};(如果是class要注意定义的函数能否调用访问ISBN成员)
bool judge(const ISBN &c,const ISBN &d){
return c.a<d.a;
}(严格若序是指,若a<b,b<c则a<c且b不能大于a)
set(ISBN,bool(*)(const ISBN &,const ISBN &))名称(judge);(使用judge是因为自动变为指针,应该使用&)
set(ISBN,decltype(judge)*)----;(这里可以用decltype指明函数返回类型再添加*表明是一个指针)
11.2.3pair类型
pair是一种标准库类型,保存于头文件utility中,pair共包含两个数据成员,创建时必须提供相对应的数据类型。
pair<t1,t2>name(v1,v2);
pair<t1,t2>name{v1,v2};
make_pair(v1,v2);(创建时根据v1,v2的类型来推断t1,t2类型)
两个容器相等时必须first与second都相等才算
返回类型为pair时可以直接写{v1,v2};不必显示的写出。
11.3关联容器操作
我们为关键字和值定义了一些类型。
key_type为关键字类型,mapped_type为map关联的类型,value_type对于set与key类型一样,对于map是pair<const key_type,mappde_type>。
11.3.1关联容器迭代器
解引用关联容器的迭代器时会获得一个value_type的引用,可以通过它访问存储值。
对于map而言value为pair类型,关键字不可修改为const。
auto iter=name.begin();
cout<<iter->first<<iter->second;(打印两个pair中两个元素)
对于set而言,value为key_type类型,虽然也可以用迭代器iterator但是也不可修改。
set<int>::iterator iter=name.begin();(虽然用iterator类型,但也不可通过解引用修改)
一般不对关联容器使用泛型算法,因为关联容器关键字不可修改。使用也是作为一个copy范围或者作为插入位置。
11.3.2添加元素
使用insert成员向关联容器添加元素或者一个范围,map和set插入重复元素无影响,内部关键字并不会增加。
name.insert(v);(向name添加v返回一个pair成员,first为一个迭代器指向给定关键字的元素,second为一个bool值,true为插入成功,false为原容器已有重复元素)
name.emplace(args);(调用args构造函数并且插入name返回值和上面一样)
name.insert(b,e);(b、e为范围,返回void)
name.insert(il);(il为列表,返回void)
name.insert(p,v);(p是提示新元素存储开始搜索的位置,返回与第一个一样)
name.emplace(p,v);(同上)
向multi添加元素时,只返回一个指向新元素的迭代器,因为允许重复。
11.3.3删除元素
关联容器删除操作除了与顺序容器一样往erase里添加一个迭代器或者一个迭代器范围(返回被删除元素之后的迭代器,范围的第二个迭代器不删除)外,还可以添加指定关键字来进行删除。
name.erase(iter);
name.erase(begin,end);(返回迭代器指向被删元素之后的那个元素,删除为范围返回第二个迭代器)
name.erase(指定元素);
11.3.4map的下标操作
我们使用下标或者at函数可以对关键字进行搜索,注意因为multi一个关键字对应多个值所以不支持,map或者unordered_map支持,如果使用下标查找,若不在,则会创建新元素并添加进去。
name[关键字];(返回的是关键字对应的左值,可以进行读或写)
map[关键字]++;(若存在,对关键字对应值加1)
name.(关键字);(返回同上,若元素不存在则会抛出out_of_range异常)
注意由于下标查找元素不在时会进行创建,所以不能对const查找不在的元素
11.3.5访问元素
关联容器提供了多种查找一个元素的方法。
name.find(k);(返回一个迭代器指向第一个为k的元素,若k不存在,则返回尾后迭代器)
name.count(k);(返回关键字的数量,若是不可重复容器,则返回1或0)
name.lower_bound(k);(返回一个迭代器,指向第一个关键字不小于k的位置)
name.upper_bound(k);(返回一个迭代器,指向第一个关键字大于k的位置)
name.equal_range(k);(返回一个pair表示关键字所在的范围,与上类似)
我们可以使用find取代下标对map的查找,因为下标会自动创建元素。
11.3.6一个单词转换的map
本节用一个示例来演示map的创建、搜索和遍历。
#include <iostream>
#include<string>
#include<map>
#include<sstream>
#include<fstream>
using namespace std;
string transform(const map<string, string> &trans_map, const string &word) { //此函数实现查找单词是否需要转换,若需要返回转化后的
auto iter = trans_map.find(word);
if (iter != trans_map.end()) {
return iter->second;
}
return word;
}
map<string, string> build_map(ifstream &ifs_map) { //此函数采用map对需要转化的词进行了存储
map<string, string> ans;
string word;
string value;
while (ifs_map >> word && getline(ifs_map, value)) {
if (value.size() > 1) {
ans[word] = value.substr(1);
}
}
return ans;
}
void word_transform(ifstream &ifs_map, ifstream &ifs_form) {
auto trans_map = build_map(ifs_map);
string text;
while (getline(ifs_form, text)) {
istringstream ss(text);
string word;
bool line = true;
while (ss >> word) {
if (line) {
line = false;
} else {
cout << " ";
}
cout << transform(trans_map, word);
}
}
}
int main() {
ifstream ifs_map(
"/home/10306785@zte.intra/10306785/upload/word_transformation_bad"),
ifs_content(
"/home/10306785@zte.intra/10306785/upload/given_to_transform");
if (ifs_map && ifs_content) {
word_transform(ifs_map, ifs_content);
}
return 0;
}
11.4无序容器
C++定义了4个无序容器,不使用比较运算符来排列关键字,使用元素类型提供的= =运算符来比较关键字,并且通过哈希函数计算关键字的哈希值将不同哈希值的元素放到不同的桶中,通常情况下我们自定义的类类型数据类型,不能直接使用无序容器,我们需要定义哈希函数和元素类型的==运算符。
c.buket_count();(正在使用的桶数量)
c.max_buket_count();(容器最多容纳桶的数量)
c.buket_size(n);(第N个桶的元素数量)
c.buket(k);(关键字为k的元素在哪个桶中)
local_iterator(用来访问桶中元素的迭代器)
const_local_iterator(const类型)
c.begin(n);c.end(n)(桶n的开始和尾迭代器)