《C++ Primer》读书笔记第十一章-1-关联容器概述

笔记会持续更新,有错误的地方欢迎指正,谢谢!

前言:前面学的都是顺序容器,顺序容器中的元素是按它们在容器中的位置来保存和访问的。接下来这一章学习关联容器:关联容器中的元素是按关键字来保存和访问的。
关联容器与顺序容器的不同之处反映了关键字的作用。

**关联容器分类:**set还是map、关键字是否重复、关键字是否有序。

使用关联容器

大多数程序员都很熟悉vector这一套,但很多人可能从未用过关联容器,接下来让大家看看关联容器在某些场合是多么牛逼。

使用map

我们要统计每个单词在输入中出现的次数:

map<string, size_t> word_count;
string word;
while(cin >> word)
{
    ++word_count[word];//[]优先级比++高 
    //你还能用顺序容器写出更简单的程序吗?
}

上一个程序的一个合理拓展是:忽略常见单词,如the,and等,我们可以用set来保存想忽略的单词:

map<string, size_t> word_count;
set<string> exclude = {"the", "and", "but"};
while(cin >> word)
{
    if(exclude.find(word) == exclude.end())
    {
        ++word_count[word];
    }
}

关联容器概述

关联容器都支持一般的普通容器操作,但是不支持顺序容器的位置相关操作,例如push_front,因为关联容器中元素是根据关键字存储的。

定义关联容器

set<string> exclude = {"1", "2"};
map<string, string> authors = {{"a", "haha"},{"b", "hehe"}}

关键字类型的要求

就是键值对,要求是:必须定义元素比较的方法,这个要求很好理解嘛。我们前面用到的键都是string或int之类的,元素比较的方法都已经默认有了。接下来就要介绍,如果键的类型是自定义的,那我们如何定义比较方法呢?
必须定义一个严格弱序(strict weak ordering)。

接下来我们就来举个例子。定义Sales_data的multiset,显然我们不能直接这样写:
multiset<Sales_data> a; //错的,因为Sales_data没有定义<运算符。

所以,我们要自定义一个比较操作,这个函数其实我们之前写过:

bool compareIsbn(const Sales_data &a, const Sales_data &b)
{
    return a.isbn() < b.isbn(); //这里能用<,还是因为isbn()返回类型是string,string有<运算符。
}

好了,现在已经自定义好比较操作了,那我们怎么让编译器知道它:

multiset<Sales_data,decltype(compareIsbn)*>bookstore(compareIsbn);

我们来仔细看看分析:

  1. 我们在定义multiset时就要在键后面加上比较操作类型,这个比较操作类型是函数指针,指向我们定义的比较操作函数。
  2. 后面bookstore加括号,意思是我们要调用compareIsbn来使bookstoe排序,什么意思呢?就是当我们添加元素时,用compareIsbn来为这些元素排序。这个小括号里的compareIsbn类型是函数指针,别忘了我们在使用函数名的时候,它会自动转化为指针。
  3. 那么问题来了,为什么前面那个compareIsbn还要加*表示指针呢?因为decltype比较特殊啊,它得出的类型是函数类型,所以要加*号表示指针。

pair类型

pair是map的好基友,我们会经常用到它,它定义在头文件utility中。 一个pair保存两个数据成员:

pair<string, string> a;
pair<string, size_t> b;
pair<string, vector<int>> c; //反正什么都能装,类似容器。

pair的默认构造函数对数据成员进行值初始化,我们也可以提供初始化器来显式初始化:

pair<string, string> d{"张无忌", "赵敏"};
//可用花括号包围的初始化器来返回pair类型的对象。

pair有个很特殊的规定它很大方,它的数据成员都是public的,而且两个数据成员分别命名为first和second。方便所有人来访问。

cout << d.first << d.second << endl;

创建返回值为pair对象的函数:

pair<string, int> process(vector<string> &v)
{
    if(v.empty()){ return {v.back(), v.back().size(); } //v不为空时,列表初始化。可用花括号包围的初始化器来返回pair类型的对象。
    else {return pair<string, int>();} //v为空时,调用默认构造函数初始化。
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值