关联容器和顺序容器的本质差别在于:关联容器通过键(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,则返回
true

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 中添加元素:

set<string> set1; // empty set
 
set1.insert("the"); // set1 now has one element

 
set1.insert("and"); // set1 now has two elements

另一种用法是,调用 insert 函数时,提供一对迭代器实参,插入其标记范围内所有的元素。该版本的 insert 函数类似于形参为一对迭代器的构造函数——对于一个键,仅插入一个元素:

set<int> iset2;  // empty set
iset2.insert(ivec.begin(), ivec.end()); // iset2 has 10 elements

与 map 容器的操作一样,带有一个键参数的 insert 版本返回 pair类型对象,包含一个迭代器和一个 bool 值,迭代器指向拥有该键的元素,而 bool 值表明是否添加了元素。使用迭代器对的insert 版本返回 void 类型。

正如不能修改 map 中元素的键部分一样,set 中的键也为 const。

// set_it refers to the element with key == 1     
set<int>::iterator set_it = iset.find(1);     
*set_it = 11; // error: keys in a set are read-only
 
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 关联容器的更多相关文章

  1. C++ Primer 笔记——关联容器

    1.关联容器支持高效的关键字查找和访问,标准库提供8个关联容器. 2.如果一个类型定义了“行为正常”的 < 运算符,则它可以用作关键字类型. 3.为了使用自己定义的类型,在定义multiset时 ...

  2. C++ Primer 随笔 Chapter 10 关联容器

    1.关联容器的类型:map(键-值对的集合,可理解为关联数组), set(单纯的键的集合), multimap(一个键对应多个值,键唯一), multiset(相同键可以是多个). 2.pair类型提 ...

  3. C++ Primer 读书笔记:第10章 关联容器

    第10章 关联容器 引: map set multimap multiset 1.pair类型 pair<string, int> anon anon.first, anon.second ...

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

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

  5. C++ Primer 5th 第11章 关联容器

    练习11.1:描述map 和 vector 的不同. map是关联容器,vector是顺序容器,关联容器与值无关,vector则与值密切相关 练习11.2:分别给出最适合使用 list.vector. ...

  6. C++ Primer笔记7_STL之关联容器

    关联容器 与顺序容器不同,关联容器的元素是按keyword来訪问和保存的.而顺序容器中的元素是按他们在容器中的位置来顺序保存的. 关联容器最常见的是map.set.multimap.multiset ...

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

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

  8. C++ Primer 学习笔记_34_STL实践与分析(8) --引言、pair类型、关联容器

    STL实践与分析 --引言.pair类型.关联容器 引言:     关联容器与顺序容器的本质差别在于:关联容器通过键[key]来存储和读取元素,而顺序容器则通过元素在容器中的位置顺序的存取元素. ma ...

  9. 《C++ Primer》笔记 第11章 关联容器

    关联容器类型 解释 按关键字有序保存元素 -- map 关联数组:保存关键字-值对 set 关键字即值,即只保存关键字的容器 multimap 关键字可重复出现的map multiset 关键字可重复 ...

随机推荐

  1. signal和sigaction 分析

    1:signal 函数 原型: sighandler_t signal(int signum, sighandler_t handler)      typedef void (*sighandler ...

  2. 杨辉三角之c实现任意行输出

    #include<stdio.h> #include<stdlib.h> int** fmalloc(int n){ int** array; //二维指针 int i; ar ...

  3. 简单的并发服务器(多个线程各自accept)

    基于之前讲述的简单循环服务器,做一个多个线程各自accept的服务器demo 由于多个线程各自accept,容易造成数据错误,需要在accept前后枷锁 先看下客户端 客户端创建socket,初始化服 ...

  4. Codeforces 833B The Bakery dp线段树

    B. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  5. helm 安装prometheus operator 并监控ingress

    1.helm安装 curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.shchmod 7 ...

  6. python析构函数

      class Test(object): def __init__(self, name): self.name = name print('这是构造函数') def say_hi(self): p ...

  7. C++字符串使用sizeof时注意

    ] = {"hello,你好"}; char tmp2[] = {"hello,你好"}; ]; sprintf(tmp3,"%s",&qu ...

  8. 枚举工具类 EnumUtils

    这是一个枚举工具类,有时候一个枚举自身为空,我们程序在调用他的方法时(如:name(),ordinal()),就会报空指针异常:下面写这个工具类就是为了来避免这些问题的,有些外部引用的没有贴出来,不过 ...

  9. IBatisNet+Oracle.ManagedDataAccess打造无需安装oracle客户端和ODP即可连接oracle数据库

    库环境: Oracle.ManagedDataAccess 版本:4.122.1.0 IBatisNet  版本:1.6.2 其实很简单的,只需在驱动配置那里添加上Oracle.ManagedData ...

  10. PHP提取链接批量下载

    2014年年初的时候,曾经受委托完成一个视频网站,那时最大的技术障碍是一个大视频比如500MB,在一个带宽环境不怎么快的服务器(比如1Mbps)上提供播放的问题. 这里会遇到两种情况,第一种情况是客户 ...