c++ primer 10 关联容器
关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,顺序容器则通过元素在容器中的位置顺序存储和访问元素
关联容器类型
map |
关联数组:元素通过键来存储和读取 |
set |
大小可变的集合,支持通过键实现的快速读取 |
multimap |
支持同一个键多次出现的 map 类型 |
multiset |
支持同一个键多次出现的 set 类型 |
pair类型
pair是一种模版类型,在创建pair对象,必须提供两个类型名。
头文件 utility
pairs 类型提供的操作
pair<T1, T2> p1; |
创建一个空的 pair 对象,它的两个元素分别是T1 和 T2 类型,采用值初始化 |
pair<T1, T2> p1(v1, v2); |
创建一个 pair 对象,它的两个元素分别是 T1 和 T2 ,其中 first 成员初始化为 v1,而 second 成员初始化为 v2 |
make_pair(v1, v2) |
以 v1 和 v2 值创建一个新 pair 对象,其元素类型分别是 v1 和 v2 的类型 |
p1 < p2 |
两个 pair 对象之间的小于运算,其定义遵循字典次序:如果 p1.first < p2.first 或者 !(p2.first < p1.first) && p1.second < p2.second,则返回 |
p1 == p2 |
如果两个 pair 对象的 first 和 second 成员依次相等,则这两个对象相等。该运算使用其元素的 == 操作符 |
p.first |
返回 p 中名为 first 的(公有)数据成员 |
p.second |
返回 p 的名为 second 的(公有)数据成员 |
pair对象的创建(三种方法:直接初始化,.firs .second ,make_pair)
10.2
- #include <iostream>
- using namespace std;
- #include <utility>
- #include <vector>
- int main()
- {
- vector< pair<string,int> > vec;
- string str;
- int n;
- cout<<"Enter a string and an integer(Ctrl +Z to end)"<<endl;
- while(cin>>str>>n)
- {
- pair<string,int> pr1(str,n);//直接创建pair对象
- vec.push_back(pr1);
- pair<string,int> pr2;//使用make_pair创建pair对象
- pr2 = make_pair(str,n);
- vec.push_back(pr2);
- pair<string,int> pr3;//用成员first,second创建pair对象
- pr3.first = str;
- pr3.second = n;
- vec.push_back(pr3);
- }
- vector< pair<string,int> >::iterator ite = vec.begin();
- while(ite != vec.end())
- {
- cout<<(*ite).first<<" "<<(*ite).second<<endl;
- ite++;
- }
- return ;
- }
map类型
定义map对象时,必须分别指明键和值的类型
map 对象的定义
map<k, v> m; |
创建一个名为 m 的空 map 对象,其键和值的类型分别为 k 和 v |
map<k, v> m(m2); |
创建 m2 的副本 m,m 与 m2 必须有相同的键类型和值类型 |
map<k, v> m(b, e); |
创建 map 类型的对象 m,存储迭代器 b 和 e 标记的范围内所有元素的副本。元素的类型必须能转换为 pair<const k, v> |
在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。 所用的比较函数必须在键类型上定义严格弱排序。所谓的严格弱排序可理解为键类型数据上的“小于”关系。对于键类型,唯一的约束就是必须支持 < 操作符
map 类定义的类型
map<K, V>::key_type |
在 map 容器中,用做索引的键的类型 |
map<K, V>::mapped_type |
在 map 容器中,键所关联的值的类型 |
map<K, V>::value_type |
一个 pair 类型,它的 first 元素具有 const map<K, V>::key_type 类型,而 second 元素则为 map<K, V>::mapped_type 类型 |
map的键值是不能修改的,必须先删除再添加
map迭代器返回value_type类型的值——包含const key_type和mapped_type类型的值
使用下标访问map对象
访问不存在的元素将导致在map容器中添加一个新元素,它的键即为该下标值
map下标操作符返回mapped_type,map迭代器返回pair类型
添加新元素可以利用下标行为的特点:
10.9 编写程序统计并输入所读入单词出现的次数
- #include <iostream>
- using namespace std;
- #include <map>
- #include <string>
- int main()
- {
- map<string,int> word_count;
- string str;
- cout<<"Enter some words(Ctrl + Z to end:)"<<endl;
- while(cin>>str)
- ++word_count[str];
- map<string,int>::iterator ite = word_count.begin();
- while(ite != word_count.end())
- {
- cout<<(*ite).first<<"\t"<<(*ite).second<<endl;
- ite++;
- }
- return ;
- }
map::insert
容器提供的 insert 操作
m.insert(e) |
e 是一个用在 m 上的 value_type 类型的值。如果键(e.first)不在 m 中,则插入一个值为 e.second 的新元素;如果该键在 m 中已存在,则保持 m 不变。该函数返回一个 pair 类型对象,包含指向键为 e.first 的元素的 map 迭代器,以及一个 bool 类型的对象,表示是否插入了该元素 |
m.insert(beg,end) |
beg 和 end 是标记元素范围的迭代器,其中的元素必须为 m.value_type 类型的键-值对。对于该范围内的所有元素,如果它的键在 m 中不存在,则将该键及其关联的值插入到 m。返回void 类型 |
m.insert(iter, e) |
e 是一个用在 m 上的 value_type 类型的值。如果键(e.first)不在 m 中,则创建新元素,并以迭代器 iter 为起点搜索新元素存储的位置。返回一个迭代器,指向 m 中具有给定键的元素 |
比如:
word_count.insert(map<string,int>value_type("a",1))
传递给 insert 的实参相当笨拙。可用两种方法简化:使用 make_pair:
word_count.insert(make_pair("Anna", 1));
或使用 typedef
typedef map<string,int>::value_type valType;
word_count.insert(valType("Anna", 1));
insert返回类型是pair对象,包含一个迭代器和一个bool。如果键已在容器中,bool返回false;不在返回true。这两种情况下迭代器都指向具有给定键的元素
也就是说insert的参数和返回值都是pair类型,返回值pair.second是bool类型
- #include <iostream>
- using namespace std;
- #include <map>
- #include <string>
- #include <utility>
- int main()
- {
- map<string,int> word_count;
- string str;
- cout<<"Enter some words(Ctrl + Z to end:)"<<endl;
- while(cin>>str)
- {
- pair< map<string,int>::iterator,bool > ret =
- word_count.insert(make_pair(str,));
- if( !ret.second )
- ++ret.first->second; //如果插入元素存在,.second加一
- }
- map<string,int>::iterator ite = word_count.begin();
- while(ite != word_count.end())
- {
- cout<<(*ite).first<<"\t"<<(*ite).second<<endl;
- ite++;
- }
- return ;
- }
以上用下标和用insert方法就是map插入元素的两种方法
查找并读取map中的元素
不修改 map 对象的查询操作
m.count(k) |
返回 m 中 k 的出现次数 |
m.find(k) |
如果 m 容器中存在按 k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器 |
注意这里对m.count(k)返回值的理解,对map,返回值只有0或者1,k出现的次数是对multimap容器
用两种方法返回.second
- int count;
- if(word_count.count('a'))
- count = word_count("a")
- map<string,int>::iterator ite = word_count.find("a");
- if(ite != word.count.end())
- count = ite->second;
注意:对于用迭代器表示map中的元素可以用(*ite).frist,等价于用ite->first,遍历的两种表示
从 map 对象中删除元素
m.erase(k) |
删除 m 中键为 k 的元素。返回 size_type 类型的值,表示删除的元素个数 |
m.erase(p) |
从 m 中删除迭代器 p 所指向的元素。p 必须指向 m 中确实存在的元素,而且不能等于 m.end()。返回 void |
m.erase(b,e) |
从 m 中删除一段范围内的元素,该范围由迭代器对 b 和 e 标记。b 和 e 必须标记 m 中的一段有效范围:即 b 和 e 都必须指向 m 中的元素或最后一个元素的下一个位置。而且,b 和 e 要么相等(此时删除的范围为空),要么 b 所指向的元素必须出现在 e 所指向的元素之前。返回 void 类型 |
set
当只想知道一个值是否存在时,使用 set 容器是最适合的。
两种例外包括:set 不支持下标操作符,而且没有定义 mapped_type 类型。在 set 容器中,value_type 不是 pair 类型,而是与 key_type 相同的类型。它们指的都是 set 中存储的元素类型。这一差别也体现了 set 存储的元素仅仅是键,而没有所关联的值。与 map 一样,set 容器存储的键也必须唯一,而且不能修改。
插入
可使用 insert 操作在 set 中添加元素:
set1.insert("the"); // set1 now has one element
set1.insert("and"); // set1 now has two elements
另一种用法是,调用 insert 函数时,提供一对迭代器实参,插入其标记范围内所有的元素。该版本的 insert 函数类似于形参为一对迭代器的构造函数——对于一个键,仅插入一个元素:
iset2.insert(ivec.begin(), ivec.end()); // iset2 has 10 elements
与 map 容器的操作一样,带有一个键参数的 insert 版本返回 pair类型对象,包含一个迭代器和一个 bool 值,迭代器指向拥有该键的元素,而 bool 值表明是否添加了元素。使用迭代器对的insert 版本返回 void 类型。
正如不能修改 map 中元素的键部分一样,set 中的键也为 const。
set<int>::iterator set_it = iset.find(1);
cout << *set_it << endl; // ok: can read the key
map 和 set 容器中,一个键只能对应一个实例。而 multiset 和 multimap 类型则允许一个键对应多个实例。 注意到,关联容器 map 和 set 的元素是按顺序存储的。而 multimap 和 multset 也一样。因此,在 multimap 和 multiset 容器中,如果某个键对应多个实例,则这些实例在容器中将相邻存放。 迭代遍历 multimap 或 multiset 容器时,可保证依次返回特定键所关联的所有元素。
小结
关联容器的元素按键排序和访问。关联容器支持通过键高效地查找和读取元素。键的使用,使关联容器区别于顺序容器,顺序容器的元素是根据位置访问的。
map 和 multimap 类型存储的元素是键-值对。它们使用在 utility 头文件中定义的标准库 pair 类,来表示这些键-值对元素。对 map 或 multimap 迭代器进行解引用将获得 pair类型的值。pair 对象的first 成员是一个 const 键,而 second 成员则是该键所关联的值。set 和 multiset 类型则专门用于存储键。在 map 和 set 类型中,一个键只能关联一个元素。而multimap 和 multiset 类型则允许多个元素拥有相同的键。
关联容器共享了顺序容器的许多操作。除此之外,关联容器还定义一些新操作,并对某些顺序容器同样提供的操作重新定义了其含义或返回类型,这些操作的差别体现了关联容器中键的使用。
关联容器的元素可用迭代器访问。标准库保证迭代器按照键的次序访问元素。begin操作将获得拥有最小键的元素,对此迭代器作自增运算则可以按非降序依次访问各个元素。
c++ primer 10 关联容器的更多相关文章
- C++ Primer 笔记——关联容器
1.关联容器支持高效的关键字查找和访问,标准库提供8个关联容器. 2.如果一个类型定义了“行为正常”的 < 运算符,则它可以用作关键字类型. 3.为了使用自己定义的类型,在定义multiset时 ...
- C++ Primer 随笔 Chapter 10 关联容器
1.关联容器的类型:map(键-值对的集合,可理解为关联数组), set(单纯的键的集合), multimap(一个键对应多个值,键唯一), multiset(相同键可以是多个). 2.pair类型提 ...
- C++ Primer 读书笔记:第10章 关联容器
第10章 关联容器 引: map set multimap multiset 1.pair类型 pair<string, int> anon anon.first, anon.second ...
- C++ Primer : 第十一章 : 关联容器之概述、有序关联容器关键字要求和pair类型
标准库定义了两种主要的关联容器:map和set map中的元素时一些关键字-值(key-value)对,关键字起到索引的作用,值则表示与索引相关的数据.set中每个元素只包含一个关键字,可以完成高效的 ...
- C++ Primer 5th 第11章 关联容器
练习11.1:描述map 和 vector 的不同. map是关联容器,vector是顺序容器,关联容器与值无关,vector则与值密切相关 练习11.2:分别给出最适合使用 list.vector. ...
- C++ Primer笔记7_STL之关联容器
关联容器 与顺序容器不同,关联容器的元素是按keyword来訪问和保存的.而顺序容器中的元素是按他们在容器中的位置来顺序保存的. 关联容器最常见的是map.set.multimap.multiset ...
- [C++ Primer] : 第11章: 关联容器
目录 使用关联容器 关联容器概述 关联容器操作 无序容器 使用关联容器 关联容器与顺序容器有着根本的不同: 关联容器中的元素是按关键字来保存和访问的, 按顺序容器中的元素是按它们在容器中的位置来顺序保 ...
- C++ Primer 学习笔记_34_STL实践与分析(8) --引言、pair类型、关联容器
STL实践与分析 --引言.pair类型.关联容器 引言: 关联容器与顺序容器的本质差别在于:关联容器通过键[key]来存储和读取元素,而顺序容器则通过元素在容器中的位置顺序的存取元素. ma ...
- 《C++ Primer》笔记 第11章 关联容器
关联容器类型 解释 按关键字有序保存元素 -- map 关联数组:保存关键字-值对 set 关键字即值,即只保存关键字的容器 multimap 关键字可重复出现的map multiset 关键字可重复 ...
随机推荐
- PID控制算法的C语言实现五 积分分离的PID控制算法C语言实现
在普通PID控制中,引入积分环节的目的主要是为了消除静差,提高控制精度.但在过程的启动.结束或大幅度增减设定时,短时间内系统输出有很大的偏差,会造成PID运算的积分积累,致使控制量超过执行机构可能允许 ...
- PID控制算法的C语言实现一 PID算法原理
本系列是转载............. 全部的程序有一个共同点:就是我没认真去调pid的参数 在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设 ...
- 基于epoll封装的事件回调miniserver
epoll技术前两节已经阐述过了,目前主要做一下封装,很多epoll的服务器都是采用事件回调方式处理, 其实并没有什么复杂的,我慢慢给大家阐述下原理. 在networking.h和networking ...
- protobuf手册
1. c++快速上手 https://developers.google.com/protocol-buffers/docs/cpptutorial 2. c++使用手册 https://develo ...
- \G,sql中select 如果太长,可以在后面放\G,竖行显示~~~~
1.使用\G按行垂直显示结果 如果一行很长,需要这行显示的话,看起结果来就非常的难受. 在SQL语句或者命令后使用\G而不是分号结尾,可以将每一行的值垂直输出. mysql> select * ...
- CF540 C BFS 水
'.'->'X' 前者走后变成后者,后者除了是终点不能再走.初始位置是X很傻的以为这样从初始点走出去后初始位置就变成不能走了,实际上是还能走一次的. 其他就是BFS,路上记得把路变成X就好了 太 ...
- python_继承.ziw
2017年1月2日, 星期一 python_继承 null
- 【CodeForces】901 C. Bipartite Segments
[题目]C. Bipartite Segments [题意]给定n个点m条边的无向连通图,保证不存在偶数长度的简单环.每次询问区间[l,r]中包含多少子区间[x,y]满足只保留[x,y]之间的点和边构 ...
- python并发编程之asyncio协程(三)
协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...
- xv6/bootasm.S + xv6/bootmain.c
xv6/bootasm.S #include "asm.h" #include "memlayout.h" #include "mmu.h" ...