C++ Primer笔记(十一)

C++ Primer 中关联容器包括map和set,通过关键字而非位置查找值。map的下标操作可创建新元素,返回pair,first为关键字,second为值。set用于存储关键字集合。关联容器不支持顺序操作,关键字类型需支持比较。无序容器使用哈希函数,通过bucket管理元素,适用于无序场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关联容器

提供了8个关联容器,其中有允许重复关键字的,multi_mapmulti_set;无序保存的unordered_mapunordered_set

使用关联容器

  1. map一般被称为关联数组,我们通过一个关键字而不是位置来查找值,而set是关键字的简单集合
map<string, size_t> word_count;
string word;
while(cin>>word)
	++word_count[word];//提取word的计数器并++;

当对map使用下标操作时,用一个string作为下标,获得与此关联的size_t计数器,如果word还未在map中,下标运算符会创建一个新元素。当从map中提取一个元素时,会得到一个pair类型的对象,用first成员保存关键字,用second成员保存对应的值

  1. 用set保存关键字的集合,可以进行列表初始化,通过find()方法查找集合当中关键字,返回一个迭代器,如果关键字不在集合中,返回尾后迭代器。

关联容器概述

关联容器都支持普通容器操作,但不支持顺序容器与位置相关的操作如push_back(),因为这对按关键字存储的关联容器没有意义

定义关联容器

  1. 定义一个map必须指明关键字类型和值类型,定义一个set指明关键字类型,可以对关联容器进行值初始化
  2. 一个map或set中的关键字必须是唯一的,但在multimap或者multiset中无此限制,

关键字类型的要求

  1. 对于有序容器,关键字类型必须定义了元素比较的方法,默认情况下,标准库使用关键字类型的<运算符来比较两个关键字,在set中关键字类型就是元素类型,在map中,关键字类型是元素第一部分的类型,是const的。
  2. 可以向一个算法提供自定义的比较操作,来替代<运算符,这一操作必须在关键字类型上定义严格弱序(可以看作小于等于)
  3. 用来组织容器中元素的操作的类型也是该容器类型的一部分,必须在定义关联容器时提供此操作的类型,用尖括号指出要定义哪种类型的容器,就必须紧跟自定义操作的类型,例如我们不能直接定义一个Sales_data类型,因为没有<运算符,但是可以用自定义函数替换:
bool compareISBN(const Sales_data& lhs, const Sales_data& rhs)
{
	return lhs.isbn()<rhs.isbn();
}
multiset<Sales_data, decltype(compareISBN)*> bookstore(compareISBN);

提供了容器中元素类型和比较操作的类型,用自定义函数来初始化bookstore对象,表明向bookstore添加元素时用compareISBN来排序

pair类型

一个pair保存两个数据成员,创建一个pair时,我们必须提供两个类型名pair<string, size_t> word_count;默认构造函数对数据成员值初始化,pair的数据成员是public的,两个分别命名为first和second, 我们可以用普通的成员访问符号来打印这两个成员

pair上的操作描述
pair<T1, T2> p;创建一个pair并进行值初始化
pair<T1, T2> p(v1,v2);创建一个pair并用v1, v2初始化
pair<T1, T2> p={v1,v2};创建一个pair并进行值初始化
make_pair(v1,v2);返回一个pair,类型由编译器推断
p.first;返回p的名为first的数据成员
p.second;返回p的名为second的数据成员
p1 relop p2关系运算符的结果关注字典序
p1 == p2当两个成员都相等时,pair才相等
  1. 返回pair的函数,可以对返回值进行列表初始化
pair<string, int> process(vector<string> &v)
{
	if(!v.empty())
		return {v.back(),v.back().size()};
	else
		return pair<string, int>();//隐式构造空返回值
}

关联容器操作

key_type容器类型的关键字类型,value_type对于set来说是关键字类型,对于map来说是pair类型,mapped_type每个关键字关联的类型

关联容器迭代器

解引用一个关联容器迭代器时,会得到一个类型为容器的value_type值的引用.

  1. set的迭代器都只允许访问set中的元素,set的关键字也是const的,可以利用迭代器读取但是不能修改
  2. map和set都支持begin和end操作,可以通过这些操作获得迭代器进而遍历容器,
  3. 我们通常不对关联容器使用泛型算法,因为关键字为const,只能用于读取元素的算法,但是效率堪忧,因为关联容器中元素不能通过关键字进行快速查找,

添加元素

  1. insert成员向容器中添加一个元素或者元素范围,由于map和set包含不重复的关键字,因此插入一个已经存在的元素对容器没有影响。
  2. 向map中添加元素时,需要注意元素的类型的pair,所以应在insert()的参数列表中创建一个pair
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_type>::value_type(word,1));

最简单的方法就是在参数列表中使用花括号初始化

插入操作简介
c.insert(v)v是value_type类型的对象
c.empalce(args)args构造一个元素
c.insert(b,e)b,e标识一个value_type类型值的范围,
c.insert(il)il是这种值的花括号列表
c.insert(p,v) c.empalce(p,args)v是value_type类型的对象,p是一个迭代器,指出从哪里搜寻新元素应当存储的位置
  1. insert的返回值依赖于容器和参数,不包含重复元素的容器insert后返回一个pair,first成员是迭代器,指向具有指定关键字的元素,second成员是一个bool值,表明插入成功(true)还是元素已经存在于容器中(false)
  2. 如果向multi_map中插入元素,调用insert总会插入一个元素,返回一个指向新元素的迭代器。

删除元素

  1. 关联容器定义了三个版本的erase,可以传入一个迭代器或者一对迭代器,提供了一个额外的erase操作,接受一个key_type参数,删除所有匹配给定关键字的元素,返回删除的数量,对于保存不重复关键字的容器,erase的返回值总是0或1,对允许重复关键字的容器,返回值可能大于1

map的下标操作

  1. map和unordered_map提供了下标运算符和对应的at函数,接受一个索引做为关键字,获得与关键字相关联的值,但如果关键字不在map中,关联值将进行值初始化,不能对multi_map进行下标操作,因为可能包含多个值。
    由于下标操作符可能插入一个新元素,所以只能对非const的map使用下标
  2. 下标操作符的返回类型是mapped_type,而解引用迭代器返回的是value_type,并且返回的是一个左值,所以也可以读或者写元素

访问元素

  1. 关联容器提供了多种查找一个指定元素的方法,对于允许重复关键字的容器,count()可能有用,使用find来替代map的下标操作,因为下标操作有一个副作用:关键字不存在时会插入一个新元素,如果只是想查找某元素用find就可以了
  2. 在multimap或者multiset中,如果多个元素具有相同的关键字,那么这些元素会相邻存储,访问的方法为:先count出某元素的出现次数,再find出该元素第一次出现的位置,再遍历容器就可找到所有具有相同关键字的;
  3. 也可以用lower_bound和upper_bound来访问,这两个方法接受一个关键字,返回一个迭代器,lower_bound返回元素第一次出现位置的迭代器,upper_bound返回最后一个元素出现位置之后的迭代器,如果元素不在multimap中,则返回相等的迭代器——一个不影响排序的关键字插入位置
  4. 需要注意的是,如果我们查找的元素具有最大关键字,则upper_bound返回尾后迭代器,如果不存在该元素且关键字最大,则lower_bound返回尾后迭代器
  5. 可以通过equal_range()接受一个关键字返回一个迭代器pair,first成员是第一个匹配的元素,second成员指向最后一个匹配元素之后的位置,若没有匹配,则两个指向相同位置

无序容器

无序容器不再使用比较运算符组织元素而是使用哈希函数,在关键字类型的元素没有明显的序的情况下,无序容器很有用,在某些应用中维护元素的序的代价很高昂,此时也很有用

  1. 无序容器在存储上组织为桶,每个桶保存0个或多个元素,使用哈希函数将元素映射到桶,为了访问元素,先计算元素的哈希值进而指出应当搜索哪个桶
  2. 对于相同的参数,哈希函数必须总产生相同的结果,理想情况下哈希函数将每个特定值映射到唯一的桶,但是将不同关键字映射到相同的桶也是允许的,无序容器提供了一系列的成员函数来管理桶
  3. 默认情况下,无序容器用关键字类型的==来比较元素,并生成每个元素的哈希值,标准库为内置类型提供了hash模板,还为智能指针,string定义了hash,所以可以直接定义关键字是内置类型的无序容器,但是不能定义关键字类型是自定义类类型,因为没有hash模板,我们应当提供函数重载哈希函数
size_t hasher ( const Sales_data& sd)
{
	return hash<string>() (sd.isbn());
}
bool eqOp(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.isbn()==rhs.isbn();
}
using SD_multiset = unordered_multiset<Sales_data,decltype(haser)*,decltype(eqOp)*>;
SD_multiset bookstore(42,hasher,eqOp);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值