关联容器的操作

除了和顺序容器定义的类型之外,关联容器还定义了一下几种类型:

关联容器额外的类型别名
 key_type    此容器类型的关键字类型
mapped_type  每个关键字关联的类型,只 适用于map
value_type 对于set,与key_type相同
对于map,为pair<const key_type, mapped_type>

关联容器的迭代器

当解引用一个关联容器迭代器时,会获得一个类型为value_type的值的引用。对于map而言,value_type是一个pair,期first成员保存const关键字,second保存值
auto map_it = words.begin();

map_it->first = "new key"; // 错误:关键字是const的
++map->second;

一个map的value_type是一个pair,我们可以pair的值,但不能改变pair的关键字。

set的迭代器时const的:虽然set定义了iterator和const_iterator类型,但是两种类型都只允许只读set的元素,与不能改变map元素的关键字一样,set的关键字也是const的。

  • 关联容器和算法
我们通常不对关联容器使用泛型算法,因为set的关键字是const的,而map的元素pair的第一个成员也是const的。因此不能将关联容器传递给修改或重排元素的算法。
实际编程中,如果我们对一个关联容器使用泛型算法,要么把它当做一个源序列,要么当做一个目的位置。例如可以用copy算法将元素从一个关联容器拷贝到另一个序列,类似的,还可以调用inserter将一个插入器绑定到一个关联容器。

添加元素

关联容器的insert操作
c.insert(v) v是value_type类型的对象,args用来构造一个元素
c.emplace(args) 对于map和set,只有当元素关键字不在c中时才会插入(或构造)元素,函数返回一个pair,包含一个迭代器,指向具有关键字的元素,以及一个指示插入是否成功的bool值。
对于multimap和multiset,总会插入(或构造)给定元素,并返回一个指向新元素的迭代器。
c.insert(b, e) b和e是迭代器,表示一个c::value_type类型值的范围,il是这种值的花括号列表,函数返回void
c.insert(il) 对于map和set,只插入关键字不在c中的元素,而multimap(set)将范围中或列表中的元素全部插入
c.insert(p, v) 类似insert(v)(或emplace(args)),但将迭代器p作为一个提示,指出从哪里开始搜索新元素应该存储的位置,返回一个迭代器,指向具有给定关键字的元素。
c.emplace(p, args)  

  • 检测insert的返回值
作为一个例子,我们利用insert重写单词计数程序:
map<string, size_t> words;
string word; while (cin >> word) { auto ret = words.insert({word, 1});
if (!ret.second)
++ret.first->second; // 增加计数
}

ret保存insert返回的值,是一个pair。

ret.first是pair的第一个成员,是一个map迭代器,指向具有给定关键字的元素。

ret.first->second 解引用此迭代器获取second值

++ret.first->second 递增该值

删除元素

关联容器定义了三个版本的erase:
关联容器删除元素
c.erase(k) 从c中删除每个关键字为k的元素,返回一个size_type值,指出删除的元素的数量
c.erase(p) 从c中删除迭代器p指定的元素,p必须指向c中的一个真实元素,不能是c.end(),函数返回一个指向p之后的元素的迭代器,若p指向c的尾元素,则返回c.end()
c.erase(b, e) 删除迭代器对b和e所表示的范围的元素,返回e

// 删除一个关键字,返回删除的元素数量
if (words.erase(removal_word))
cout << removal_word << "removed" << endl;
else
cout << removal_word << "not found" << endl;

对于保存不重复关键字的容器,参数为key_type的erase版本总是返回0或1,而对于保存可以重复关键字的容器,删除元素的数量可能大于1。

map的下标操作

map和unordered_map定义了下表运算符和at成员函数。set不支持下标,因为set中没有与关键字相关联的值,我们不能对multi-系列的map执行下标操作,因为这两个容器里关键字可以重复。
map和unordered_map的下标操作
c[k] 返回关键字为
k的元素,如果k不在c中,添加一个关键字为k的元素,对其进行值初始化
c.at(k) 访问关键字为k的元素,带参数检查:若k不在c中,抛出一个out_of_range异常

map<string, size_t> words;
// 插入一个关键字为Anna的云阿苏,关联值进行值初始化,然后将1赋予它
words["Anna"] = 1;

由于下标操作可能会插入元素,因此我们只能对非const的map或unordered_map使用下标操作

成员函数at在找不到关键字的时候抛出异常,因此我们可以这样做 : 当我们只是想在一个map或unordered_map中查找关键字为k的元素时,使用at成员函数;  如果我们还想插入这个不存在的关键字为k的元素时,就使用下标操作。

  • 使用下标操作的返回值
map的下标操作和其他类型的下标操作的另一个不同之处是返回类型,正常情况下,解引用一个迭代器所返回的类型与下标运算符返回的类型是一样的。但对map而言,下标操作返回的类型时mapped_type类型,而解引用迭代器返回的是value_type类型。

访问元素

在一个关联容器中查找元素的操作:
lower_bound和upper_bound不适用于无需容器
下标和at操作只适用于非const的map和unordered_map c.find(k); 返回一个迭代器,指向第一个关键字为k的元素,若k不在c中,返回尾后迭代器。
c.count(k); 返回关键字等于k的元素的数量,对于不允许重复关键字的容器,总是返回0或1
c.lower_bound(k); 返回一个迭代器,指向第一个关键字不小于k的元素
c.upper_bound(k); 返回一个迭代器,指向第一个关键字大于k的元素
c.equal_range(k); 返回一个迭代器pair,表示关键字等于k的元素的返回,若k不存在,pair的两个成员均等于c.end()
  • 对map使用find操作代替下表操作
有时候,我们只是想知道一个给定关键字的元素是否存在于map中,如果不存在,下标操作会插入此元素,这会偏离我们的预想,我们可以使用find操作来判断给定关键字的元素是否在map中:
if (words.find(k) == words.end())
cout << "k is not in the map!" << endl;
  • 在multimap或multiset中查找元素
在一个不允许重复关键字的关联容器里查找给点关键字的元素很容易,但是对于允许重复关键字的关联容器来说,过程更为复杂,在容器中可能有很多元素的关键字都和给定的关键字相等。如果一个multimap或multiset中有多个元素具有给定关键字,则这些元素会相邻存储。 我们在遍历一个multimap或multiset时,保证可以得到序列中所有序列中给定关键字的元素。
string search_item("Alain de Botton"); // 要查找的作者
auto entries = authors.count(search_item); // 作者的著作
auto iter = authors.find(search_item); // 作者的第一本书 while (entries) {
cout << iter->second << endl;
++iter;
--entries;
}
  • lower_bound 和 upper_bound

我们还可以用lower_bound和upper_bound,lower_bound接受一个关键字,返回指向第一个具有给定关键字的元素的迭代器,而upper_bound返回指向最后一个具有给定关键字的元素之后的元素的迭代器。
如果关键字不在容器中,则lower_bound 和upper_bound会返回相等的迭代器——指向一个不影响排序的关键字插入位置。如果我们查找的关键字具有容器最大的关键字,则此upper_bound返回尾后迭代器,如果关键字不存在且大于容器最大的关键字,则lower_bound和upper_bound都返回尾后迭代器。

for (auto beg = authors.lower_bound(serch_item), end = authors.upper_bound(search_item); beg != end; ++beg)
cout << beg->second << endl;

如果lowerbound和upperbound相等,则给定关键字不存在容器中。

  • equal_range函数
我们还可以使用equal_range来解决上面的问题,此函数接受一个关键字,返回一个迭代器的pair,若关键字不存在,pair中的迭代器都指向关键字可以插入的位置;如果关键字存在,第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配的元素之后的位置。
for (auto pos = authors.equal_range(search_item); pos.first != pos.second; ++pos.first)
cout << pos.first->second << endl;

C++ Primer : 第十一章 : 关联容器之关联容器的迭代器和操作的更多相关文章

  1. C++Primer 第十一章

    //1.关键容器支持高效的关键字查找和访问. map 关联数组:保存关键字-值对.通过关键字来查找值. set 关键字即值,即只保存关键字的容器. multimap 关键字可重复出现的map mult ...

  2. C++ Primer : 第十一章 : 关联容器之概述、有序关联容器关键字要求和pair类型

    标准库定义了两种主要的关联容器:map和set map中的元素时一些关键字-值(key-value)对,关键字起到索引的作用,值则表示与索引相关的数据.set中每个元素只包含一个关键字,可以完成高效的 ...

  3. C++ Primer : 第十一章 : 关联容器示例: 一个单词转换的map

    单词转换就是:将一些缩写的单词转换为实际的文本.第一个文件保存的是转换的规则,而第二个文件保存的是要转换的文本. 假设单词转换的规则的文件如下: brb be right back k okay? y ...

  4. 第十一章、认识与学习 BASH Bash Shell 的操作环境

    bash中的变量动不动就说环境变量,真是奇怪,bash只是一个c语言编写的程序而已,跟环境变量有什么关系?如果知道dos的历史的话就知道有个时代是只有命令行界面而没有图形用户界面,这只小小的程序就包揽 ...

  5. [C++ Primer] : 第11章: 关联容器

    目录 使用关联容器 关联容器概述 关联容器操作 无序容器 使用关联容器 关联容器与顺序容器有着根本的不同: 关联容器中的元素是按关键字来保存和访问的, 按顺序容器中的元素是按它们在容器中的位置来顺序保 ...

  6. 【C++】《C++ Primer 》第十一章

    第十一章 关联容器 关联容器和顺序容器的不同:关联容器中的元素时按照关键字来保存和访问的. 关联容器支持通过关键字来高效地查找和读取元素,基本的关联容器类型是 map和 set. 类型 map 和 m ...

  7. [C++ Primer] 第9章: 顺序容器

    顺序容器概述 顺序容器的类型有: 类型 说明 vector 可变长度数组. 支持快速随机访问. deque 双端队列. 支持快速随机访问. list 双向链表. 只支持双向顺序访问. forward_ ...

  8. 【WPF学习】第二十一章 特殊容器

    内容控件不仅包括基本控件,如标签.按钮以及工具提示:它们还包含特殊容器,这些容器可用于构造用户界面中比较大的部分区域. 首先介绍ScrollViewer控件,该控件直接继承自ContentContro ...

  9. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

随机推荐

  1. Debug的F5~F8用法

    快捷键(F6)单步执行程序,遇到方法时跳过. 快捷键(F8)执行此断点到最后,进入下一个断点开始之处. 快捷键(F5)单步执行程序,遇到方法时进入. 快捷键(F7)单步执行程序,从当前方法跳出.

  2. Diskpart使用说明

    [查看硬盘信息] 1.打开命令窗口 cmd 2.diskpart 命令进入Diskpart管理程式 3.list disk 查看硬盘信息   list partition 查看分区信息 [初使化硬盘] ...

  3. 租房时代,K2 BPM软件带你拥抱更好生活

    提到租房子,你的第一反应肯定就是心酸的找房路,奇葩的极品房东……但租房对于年轻人来说又是生存路上必须面对的挑战.现在有一家公司想给你一段租房时代的美好回忆,它就是优客逸家. 优客逸家,隶属于四川优客投 ...

  4. redis2.8--内存管理

    总而言之,redis内存管理是采用主要由操作系统自主控制内存分配,辅之以简单封装,达到简单且稍微改良的性能. 内存块,标记上本块size 如上图所示, 当调用zmalloc/zmalloc时,输入参数 ...

  5. 经典线程同步 信号量Semaphore

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  6. vs2012 .netFramwork2.0发布到xp

    开发环境 windows server2008R2 VS2012  .net Framwork2.0 开发的winform程序 在有的xp系统下不能运行 选择 项目属性=>编译 Build=&g ...

  7. Ubuntu 14.10 下开机不进入图形化界面

    因为装的是Ubuntu 桌面版,很占资源,所以启动时候不进入图形化界面,肯定会省不少内存 进入  /etc/X11/default-display-manager  sudo nano/etc/X11 ...

  8. (转)phoneGap-Android开发环境搭建

    (原)http://www.cnblogs.com/shawn-xie/archive/2012/08/15/2638480.html phoneGap-Android开发环境搭建   一.安装 在安 ...

  9. hdu 2076

    ps:WA了三次...第一次头脑有点乱,很麻烦的分几种情况讨论,第二次发现,只要分别算出时针和分针的角度,然后一减就行,却忽略了哪个大的问题,第三次加上了绝对值,就好了..就是以后double型比较最 ...

  10. hdu 2053

    Ps:找规律题....凡是平方数都是开...WA了一次..数组给的太小?...后来给到3000..就AC了 代码: #include "stdio.h"long long dp[3 ...