[C++ Primer Note10] 关联容器

关联容器和顺序容器的本质区别在于:关联容器中的元素是按关键字来保存和访问的,而顺序容器是按它们在容器中的位置来顺序保存和访问的。

  1. 标准库提供8个关联容器

按关键字有序保存元素

  • map
  • set
  • multimap
  • multiset

无序集合

  • unordered_map
  • unordered_set
  • unordered_multimap
  • unordered_multiset

其中,multi表示允许重复关键字。map和multimap定义在头文件map中;set和multiset定义在set中;无需容器定义在头文件unordered_mapunordered_set中。

  1. 一个经典的使用关联容器的例子是单词计数程序
map<string,int> word_count;
string tmp;
while(cin>>tmp){
    ++word_count[tmp];
}

for(const auto &w:word_count){
    cout<<w.first<<":"<<w.second<<endl;
}

一旦读取完所有输入,范围for语句就会遍历map,当从map中提取一个元素时,会得到一个pair类型的对象,它是一个模板类型,保存两个名为firstsecond的公有数据成员,前者为key,后者为value

  1. 上一个程序的一个合理拓展是:忽略常见单词,我们可以使用set保存想忽略的单词,只对不在集合中的单词统计出现次数:
map<string,int> word_count;
set<string> exclude={"The","But","And"};
string tmp;
while(cin>>tmp){
    if(exclude.find(tmp)==exclude.end())
        ++word_count[tmp];
}

set的find成员返回一个迭代器。如果给定关键字在set中,迭代器指向该关键字。否则,find返回尾后迭代器

  1. 对于有序容器,关键字类型必须定义元素比较的方法,默认情况下,标准库使用关键字类型的<运算符来比较两个关键字。当然也可以自定义比较规则:
multiset<Sales_data,decltype(compareIsbn)*> bookstore(compareIsbn);

需要提供比较操作类型(一种函数指针类型),以及在构造函数中传入比较函数

  1. pair标准库类型,定义在头文件utility中,一个pair保存两个数据成员。pair的默认构造函数对数据成员进行值初始化,我们可以这样初始化pair:
pair<string,string> author{"james","kevin"};
pair<int,string> student(1,"kevin");
  1. 关联容器额外定义了几个类型别名
  • key_type:关键字类型
  • mapped_type:每个关键字关联的类型
  • value_type:对于set,就是key_type;对于map,是pair类型
  1. 当解引用一个关联容器迭代器时,我们会得到一个类型为容器的value_type的值得引用。
  2. set的迭代器是const的 ,无论是iterator还是const_iterator。而map的pair中的第一个成员也是const的。
  3. map和set类型都支持前述的beginend操作,对于有序关联容器来说,按照关键字升序遍历。
  4. 我们通常不对关联容器使用泛型算法,关键字是const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法。对于搜索算法而言,泛型算法是顺序搜索,而关联容器内部定义的find成员根据关键字搜索会快得多。
    一般来说,仅在把关联容器当作源序列或者目的位置的时候才使用泛型算法。
  5. 添加元素
    添加元素
// 插入一个元素到map中
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));
  1. insert(或emplace)返回值依赖于容器类型和参数,对于不包含重复关键字的容器,添加单一元素的insert和emplace返回一个pair,first成员是一个指向给定关键字的迭代器(即使插入失败),second成员是一个bool,如果插入之前key已经存在返回false,否则插入成功返回true。对于允许重复关键字的容器,insert操作仅仅返回一个指向新元素的迭代器,没有bool值
  2. 删除元素
    删除元素
  3. map的下标操作
    下标操作

    我们不能对multi版本的map进行下标操作,因为可能有多个值相关联。
    下标运算符在关键字不存在的情况下会创建元素并插入到map
  4. 与迭代器不同,map的下标操作返回的是mapped_type而不是解引用迭代器得到的value_type
  5. 查找元素
    查找元素

    我们可以通过lower_boundupper_bound找到一个关键字相同的序列(对于multi来说)
  6. 新标准定义了4个无序关联容器,这些容器不是使用比较运算符(树)来组织元素,而是使用哈希函数和关键字类型的==运算符。在关键字类型的元素没有明显的序关系的情况下,无序容器非常有用。
    无序容器无非就是一组桶,除了提供与有序容器相同的操作之外,它还提供了一组管理桶的成员函数,这些成员函数允许我们查询容器的状态以及在必要时强制容器进行重组:
    无序容器管理操作
  7. 默认情况下,无序容器使用关键字类型的==运算符来比较元素,它们还使用一个hash<key_type>类型的对象来生成每个元素的哈希值。标准库为内置类型(包括指针)提供了hash模板。还为一些标准库类型,包括string和智能指针类型定义了hash。因此,我们可以直接定义关键字是内置类型,string以及智能指针的无序容器。
  8. 但是,我们不能直接定义关键字类型为自定义类型的无序容器,与容器不同,不能直接使用哈希模板,而必须提供我们自己的hash模板版本。但我们可以使用类似于为有序容器重载关键字类型的方法提供函数代替==运算符和哈希值计算函数去实现同样的效果。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358

推荐阅读更多精彩内容

  • #include set,multiset #include map,multimap #include unor...
    龙遁流阅读 344评论 0 2
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,521评论 1 51
  • 九.顺序容器 顺序容器的顺序表示元素插入的顺序 C++标准库容器提供了顺序访问元素的能力,但是不同的容器在以下的操...
    m风满楼阅读 367评论 0 0
  • 在 ion-card中,有时候ion-item的高度对于手机来说有点高,有两个地方可以调整,可以同时更改两个参数,...
    美味小鱼阅读 3,956评论 1 0
  • 我走进教室,我觉得教室里又闷又热,仿佛被502胶水凝固了,我非常难受,我好像在沙漠中,那里非常热,我快被shai死...
    摩天大楼8岁阅读 282评论 0 0