C++Primer第十一章:关联容器

第十一章:关联容器

关联容器与顺序容器不同之处在于顺序容器是按在容器中的位置保存和访问元素,而关联容器是按关键字来保存和访问元素的。

一.使用关联容器

当从map中提取一个元素时,会得到一个pair类型的对象。

二.关联容器概述

关联容器的迭代器都是双向的。

对于有序容器,关键字类型必须定义元素比较的方法。我们也可以自己定义比较操作来代替<运算符,所提供的操作必须是严格弱序

自定义的操作类型必须在尖括号中紧跟着元素类型给出。要注意的是尖括号里面的操作是一种类型,而不是具体的对象,所以我们要给函数指针,这个指针不是指向某个具体的函数,而是代表一种函数类型。

pair是一种标准库模板类,它定义在头文件utility中。可以用make_pair来生成pair对象,pair对象的两个类型来源于参数。

三.关联容器操作

相对于顺序容器,关联容器还定义了三种类型:key_type, mapped_type, value_type。

当解引用一个关联容器的迭代器时,得到的是一个类型为value_type的引用。对map而言,value_type是pair类型,且pair的first是const的。set的关键字(值)也是const的,所以set的迭代器只能读不能写。

我们通常不对关联容器使用泛型算法,因为其有const的特性。关联容器可用于只读取元素的算法,不过关联容器本身也定义了一些算法。在实际应用中,如果要对关联容器使用算法,一般要么把它当作原序列,要么当作目的位置,例如把一个关联容器copy到另一个关联容器。

由于下标运算符可能插入一个新元素,我们只可以对非const的map使用下标操作。

四.无序容器

无序容器在存储上组织为一组桶,元素通过哈希函数映射到某个桶上,一个桶可能有多个元素,这个时候就需要顺序搜索了。无序容器也提供了一系列接口来操作桶。

要使用为某个类型创建对应的无序容器类型,要满足两个条件,一是有==运算符,二是能够被无序容器的哈希函数计算出哈希值。如果不满足的话就要自己定义相等的函数和定义计算哈希值的函数。

练习

发现了C++Primer5th的官方代码网站,书上的代码都有C++ Primer, 5th Edition Source Downloads

11.1

map是按关键字保存和访问元素,而vector是按元素在容器中的位置。

11.2

答案

11.3

int main() {
    unordered_map<string,int> record;
    string temp;
    while (cin >> temp) {
        ++record[temp];
    }
    return 0;
}

11.4

答案

11.5

当需要查找给定值所对应的数据时,应使用 map,其中保存的是 <关键字, 值> 对,按关键字访问值。

如果只需判定给定值是否存在时,应使用 set,它是简单的值的集合。

11.6

两者都可以保存元素集合。

如果只需要顺序访问这些元素,或是按位置访问元素,那么应使用 list。

如果需要快速判定是否有元素等于给定值,则应使用 set。

11.7

int main() {
    map<string, vector<string>> family = {{"Li", {"Hua", "Xiao"}}, {"Tang", {"Fen", "Hu"}}};
    family.insert({"Zhang", {"yu", "san"}});
    family["Li"].push_back("Yun");
    return 0;
}

11.8

答案

11.9

map<string, list<int>> my_map;

11.10

按道理,list::iterator是不能比较的,但是我的编译器能够通过。。。但是这个题主要考的是map的关键字要能比较。

11.11

typedef bool (*pf) (Sales_data &lhs, Sales_data &rhs);

int main() {
    auto f = [](Sales_data &lhs, Sales_data &rhs) -> bool{return lhs.isbn() < rhs.isbn();};
    multiset<Sales_data, pf> bookstore(f);
    return 0;
}

11.12

int main() {
    vector<pair<string, int>> vec;
    string str;
    int i;
    while (cin >> str >> i) {
        vec.push_back({str, i});
    }
    return 0;
}

11.13

vec.push_back({str, i}); // 最简洁
vec.push_back(make_pair(str, i));
vec.push_back(pair<string, int>(str, i));

11.14

map<string, vector<pair<string, string>>> family;

11.15

mapped_type:vector
key_type:int
value_type:pair>

11.16

int main() {
    map<int, int> test{{1,1}};
    auto be = test.begin();
    be->second = 2;
    cout << test.begin()->second << endl;
    return 0;
}

11.17

就第二个是错的,因为map没有push_back这个方法。

11.18

map::iterator

11.19

typedef bool (*pf) (Sales_data &lhs, Sales_data &rhs);

int main() {
    auto f = [](Sales_data &lhs, Sales_data &rhs) -> bool{return lhs.isbn() < rhs.isbn();};
    multiset<Sales_data, pf> bookstore(f);
    multiset<Sales_data, pf>::const_iterator it = bookstore.begin();
    return 0;
}

11.20

答案

下标的方式更加简洁易读。

11.21

单词计数。统计各个单词出现的次数。

11.22

参数类型:pair>
返回类型:pair>::iterator, bool>

11.23

multimap family;

11.24

相当于插入了一个{0, 1};如果本来有关键字0,则是修改关键字0对应的值为1.

11.25

把v的第0个元素值置为1,如果v没有这么多元素,是越界行为,行为未定义。

11.26

答案

11.27

对于map和set判断是否存在可以用count也可以用find,而要具体得到指向值的迭代器用find,要查找数目用count。

11.28

map> test;
map>::iterator it = test.find("1");

11.29

答案

11.30

pos是一个pair类型,其first是一个迭代器,指向map中相对应的元素,再其second就是具体的值。

11.31

int main() {
    multimap<string, string> test = {{"zhang", "good, bad, ugly"}};
    if (test.find("zhang") != test.end()) {
        test.erase("zhang");
    }
    return 0;
}

11.32

答案

11.33

答案

11.34

就算s本来不存在于m中,如果m为非const,使用下标运算符也会创建一个关键字为s的对象,这样单词的替换就会出现问题,把不该替换的替换了。书中m为const,所以会报错。

11.35

如果有多个重复的关键字,下标会更新内容而insert不会,所以如果有多个关键字相同的转换规则,那么insert会保留第一个。

11.36

书中的程序其实已经处理了这种情况,即value.size() > 1,如果没有处理,则该关键字对应的转换为空字符串。

11.37

无序容器性能更好,有序容器可以维持有序

11.38

答案

你可能感兴趣的:(C++Primer笔记,c++,开发语言,C++Primer)