c++primer阅读笔记之关联容器学习

关联容器

关联容器简述

  1. 关联容器通过键(key)存储和读取元素,而顺序容器通过元素在容器中的位置顺序存储和访问元素。关联容器最独特的地方在于其支持键的使用;
  2. 如果希望有效的存储不同值得集合,那么使用set容器比较合适,而map容器则更适用于需要存储每个键所关联的值的情况;

Pair类型

Pair基本操作

Pair类型变量的创建方式

  • 调用Pair类型的构造函数
    a) Pair< T1, T2 > p1,该构造函数创建一个Pair变量p1,其中该变量的第一个元素是T1类型,第二个元素是T2类型,该变量采用值初始化,即如果T1为string类型,那么就初始化为一个空字符串,如果T2是一个int类型,则初始化为0;
    b) Pair< T1, T2 > P1(v1, v2),改构造函数创建一个Pair变量p1,两个元素分别为T1和T2类型,我们把第一个元素的值设为v1,第二个元素的值设为v2
    c) 注意点:
    i. 首先,我们要注意在创建Pair对象的时候,一定要提供变量类型,两个元素的类型可以是不一样的;
    ii. 我们在定义多个相同类型的Pair变量的时候,我们可以利用typedef来简化定义过程:
    typedef pair< T1, T2 > a;
    a n1(t1, t2);
    a n2(t1, t2);
    这里我们定义了两个变量n1与n2,其类型为pair< T1, T2 >类型
    iii. 对于pair类型,其元素是公有的,即我们可以通过点(.)操作符直接访问pair对象的两个元素,因此我们可以直接以输入的形式为两个元素赋值,即我们先声明该对象,然后再赋值:
pair< T1, T2 > a;
cin >> a.first >> a.second;
  • 调用make_pair函数
    a) make_pair(v1, v2),该函数以v1和v2值创建一个新的pair对象,其两个元素类型分别于v1和v2的相同
    b) 使用make_pair函数来定义pair对象要比构造函数的方式方便很多,因此常用make_pair方式

Pair类型元素访问方式

由于pair类型的元素是公有的(public),因此我们可以直接通过点(.)操作符来访问,即我们可以通过p.first来访问第一个元素,通过p.second来访问第二个元素

Pair类型的比较

我们可以对pair类型的对象进行比较,比较原则如下:
Pair类型的比较运算时遵循与字典次序的,即首先比较第一个元素,如果第一个元素相同,则再比较第二个元素,因此如果p1.first < p2.first,那么p1 < p2,如果不小于,那么比较第二个元素,如果p1.second < p2.second,则p1 < p2;
如果想要p1 == p2,我们需要p1.first == p2.first && p1.second == p2.second

Pair类型对应的头文件

#include<utility>

Pair类型注意事项

  1. Pari类型并没有重定义<<输出操作符,因此我们不可以直接利用该操作符输出pair的值,即我们不可以直接cout << p,要想输出p的值,我们需要cout << p.first << p.second来实现

map类型

map容器简述

  • map是键值对集合
  • map类型为一个关联数组,即其可以使用键作为下标来获取一个值
  • 关联的本质在于元素的值与某个特定的键相关联,而非通过元素在数组中的位置来获取

map对象的定义

map对象定义注意点:

  • 首先,在定义map对象时,要指明map对象的键和值的类型,即要在定义时为map< K, V > pm格式;
  • map对象的键应该是const类型的,即键是不可修改的;
  • map对象的键必须支持 < 操作符
  • map迭代器的解引用得到的并不是map的值成员,而是一个指向容器中一个value_type类型的值的引用,这与vector类型很不一样,这也导致了map类型的解引用得到的值与下标操作符得到的值是不一样的,而vector类型中,这两种操作得到的值则是一样的

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类型进行元素插入操作有两种方法:

  • 下标访问法(与vector最不同的地方之一,vector不能使用下标操作实现插入)
  • 调用函数insert()法

下标访问法能够实现插入操作的主要原因是:
对于map类型来说,如果使用下标操作符利用键访问不存在的元素的时候,要利用该键创建新的键值对插入对应的map对象中,该建对应的值采用值初始化。因此使用下标可以实现插入操作。但是要注意,使用下标操作符在访问存在的元素的时候,可能改变该下标对应的值,而insert()方法则不会发生这样的问题,其访问存在的元素不会改变值。

insert操作

  • m.insert(e)
    • e是一个用在m上的value_type类型的值。如果键e.first不在m中,则插入一个值为e.second的新元素;如果存在,则保持m不变
    • 该函数返回一个pair类型的对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素(如果元素不存在,则bool值为true,如果已经存在,则其值为false)
  • m.insert(beg, end)
    • beg和end是标记元素范围的迭代器。对于该范围内的所有元素,如果它的键m不存在,则将该键及其关联的值插入到m
    • 返回void类型
  • m.insert(iter, e)
    • e是一个用在m上的value_type类型的值。如果键e.first不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置
    • 返回一个迭代器,指向m中具有给定键的元素

查找操作

对map来说,查找操作有三种方式可以实现:

  • 下标查找法(下标查找法很少使用,因此使用该方法,在没有的情况下,其会插入新的元素,如果在没有查到的情况下不需要插入新元素的话,是不能使用下标查找法的)
  • 利用count函数查找
  • 利用find函数查找

m.count(k),返回的是键k出现的次数,当返回的为0时,则说明该键不存在,当返回非0,则该键存在,通过该函数只能指出是否存在以及有多少个这样的键,但是无法确定具体的位置(要注意,在map的操作中,都是对键k进行操作)
m.find(k),如果m容器中存在按k索引的元素,则返回指向该元素的迭代器(这个迭代器是map< k, v >类型)。如果不存在,则返回超出末端迭代器
注:只要是使用了下标符进行操作,就一定会执行查找操作

删除操作

对map类型的对象执行删除操作通常是使用erase函数,但是map的erase函数与vector的erase函数的返回值有所不同,map的erase函数返回的是void或者删除元素的个数,而vector的erase函数返回的则是指向被删元素后面元素的迭代器

erase操作

  • 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指向的元素的前一个元素
    • 如果b和e相等,则不执行删除操作
    • 返回void类型

set类型

set容器简述

  • 相比于map容器,set容器只是单纯的键集合,但是set又与vector不同,vector中的元素可以有重复的,但是set容器中的键不可以有重复的,即每一个键都必须是唯一的,这与map对键的要求是一样的。
  • set容器支持map容器中的insert,count,find以及erase操作,因此有关set的插入,查找和删除操作可以参考map类型(除了下标的方法,其余的都一样),但是其不支持下标操作符,且没有定义mapped_type类型
  • 在set容器中,其value_type不是pair类型,而是与key_type相同的类型

multimap和multiset类型

multimap和multiset类型简述

相较于map和set类型,multi* 类型允许一个键对应多个实例,而且这些实例在容器中相邻存放,即同一个键所关联的元素均相邻存放。但是multi*不支持下标操作,这很好理解,因为一个键对应多个实例,那么这时候我们基于键进行查找的时候,是无法确定要取哪个值的

insert,erase,find,count等操作的变化

  • insert:由于一个键对应多个值,所以在multi*中使用insert操作时,即使存在也会执行插入操作,即每次调用总会添加一个元素
  • erase
    • m.erase(k)这样带有一个参数的删除操作,将会删除拥有该键的所有元素,并返回删除元素的个数
    • m.erase(b,e)这样带有迭代器的删除操作,只删除指定的元素,返回void类型
  • count:count操作会求出某键出现的次数,这与非multi一样
  • find:find操作会返回一个迭代器,指向第一个拥有正在查找的键的实例

multi*所特有的操作

  • m.lower_bound(k):
    • 返回一个迭代器,指向键不小于k的第一个元素
  • m.upper_bound(k):
    • 返回一个迭代器,指向键大于k的第一个元素
  • m.equal_range(k):
    • 返回一个迭代器的pair对象,其first成员等价于m.lower_bound(k)。而second成员则等价于m.upper_bound(k),该方法将产生一个迭代器范围,指出该键所关联的所有元素

你可能感兴趣的:(C++)