C++ 小白 学习记录11

本文介绍了C++中map、set及其unordered系列容器的使用,包括它们的特点(如关联数组、关键字唯一或多、有序/无序),以及如何通过自定义哈希函数和比较操作进行操作。重点讲解了map和set的迭代、添加删除、下标访问及无序容器的管理技巧。

第十一章  关联容器

map 和 set

map 头文件map, set和multiset 头文件set, unordered 系列在在unordered_map, unordered_set中

map 键值对, set 只保存关键字(当只想知道一个值是否存在时, set是最有用的.)

带multi 表示关键字可以重复的, 带unordered 表示无序的

无序容器 使用哈希组织

map 关联数组, 却别在于map下标不必是整数

  • map                关联数组  键值对
  • set                        关键字即值, 只保存关键字的容器
  • multimap                关键字可重复的map
  • multiset                        关键字可重复的set
  • unordered_map                用哈希函数组织的map
  • unordered_set                        用哈希函数组织的set
  • unordered_multimap                哈希组织的map, 关键字可重复
  • unordered_multiset                        哈希组织的set, 关键字可重复

有序容器关键字的 必须遵循严格弱序 规则. 

如果一个类没有定义< 运算符, 则不能使用multiset/ set , 可以使用类内可以比较的函数替代. 如不能直接定义Sales_data的multiset, 但是因为Sales_data中定义的compareIsbn 在isbn上定义了一个严格弱序. 此时定义multiset需要提供两个类型: 关键字类型以及比较操作类型 - 一种函数指针类型.

multiset<Sales_data, decltype(compareIsbn) *> bookstore(compareIsbn);

当使用decltype来获取函数指针类型时, 必须加上一个*来指出我们要需要一个给定函数类型的指针.

当使用一个函数的名字时, 在需要的情况下它会自动转化为一个指针. 类似于数组

关于 11.10:  vector<int> 是双向迭代器, 其定义了比较运算符<, 可以作为 map的关键字. 而 list<int> 是双向迭代器, 没有定义<, 所以不能作为关键字

vector<int> -> _Vector_iterator<_Scary_val> -> _Vector_const_iterator<_Myvec> ->

_NODISCARD bool operator<(const _Vector_const_iterator& _Right) const noexcept {
        _Compat(_Right);
        return _Ptr < _Right._Ptr;
    }

list<int> -> _List_iterator<_Scary_val> -> _List_const_iterator<_Mylist>  该类中未定义 < 运算符

pair类型(utility头文件)

make_pair(key, value) 返回一个pair

pair和map的区别: map 是容器 pair 是一种类型

关联容器的操作

  • key_type                容器类型的关键字类型 严格弱序
  • mapped_type        每个关键字关联的类型 只适用于map
  • value_type              map: 是一个pair<const key_type, mapped_type> 

此处与通常的key-value类型有所不同, 通常意义上的key 则使用key_type, value使用value_type 来获取类型, 而此处不同的是value 为mapped_type,  value则指的是<key, value>的pair类型.

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

set的迭代器是const的.

添加元素:

map/set 插入一个关键字已经存在的元素 则没有任何影响.

  • mapx.insert({word, 1})
  • mapx.insert(make_pair(word,1));
  • mapx.insert(pair<string, size_t>(word,1));
  • mapx.insert(map<string,size_t>::value_type(word,1));
  • mapx.emplace(args) 返回一个pair, 包含一个迭代器和插入是否成功的bool值

删除元素

  • mapx.erase(k)        删除关键字是k的所有元素, 返回删除元素的个数size_type
  • mapx.erase(p)        删除迭代器p指定的元素. 返回指向p之后元素的迭代器.
  • mapx.erase(b,e)        删除迭代器b e表示的范围, 返回e

map的下标操作

如果下标不存在则会创建该下标为关键字的元素. 如果只是判断关键字是否存在,则一定不能使用下标

map.at(k)  不存在k, 则会抛出out_of_range的异常

下标运算返回值是mapped_type对象, 解引用获取的是value_type 对象, 可以这么理解, 下标运算代表已经知道了关键字, 则无需返回关键字, 而解引用 则不知道关键字和值, 所以返回pair中第一部分为关键字, 第二部分为值

访问元素

  • 下标, at 只适用 非const的map和unordered_map
  • c.find(k)        返回找的迭代器, 否则end()
  • c.count(k)        返回 k的个数
  • c.lower_bound(k)   返回一个迭代器, 指向第一个关键字不小于k的元素  有序容器
  • c.upper_bound(k)  返回一个迭代器, 指向第一个关键字大于k元素 有序容器
  • c.equal_range(k) 返回迭代器pair, 关键字等于k的元素范围, k不存在, pair的两个成员都等于end()

lower_bound, upper_bound 相当于过滤关键字的所有元素, 返回是迭代器.

beg = lower_bound(k), end = upder_bound(k);

假如有多个元素与给定关键字匹配, 则beg指向第一个元素,  通过递增beg来遍历这些关键字元素, 当beg等于end时, 遍历完成

multimap, multiset 相同关键字的元素会相邻存储

equal_range(k) 根据关键字k返回一个迭代器pair,  当pair中的两个迭代器相同时, 则没有该关键字, 否则两个迭代器的范围就是所有的关键字元素.

无序容器

无序容器提供了和有序容器相同的操作: find, insert等.

管理桶

无序容器管理操作

桶接口:

  • c.bucket_count()        正在使用的桶的数量
  • c.max_bucket_count()        容器能容纳的最多的桶数量
  • c.bucket_size(n)        第n个桶中有多少个元素
  • c.bucket(k)        关键字为k的元素在哪个桶中

桶迭代:

  • local_iterator        可以用来访问桶中元素的迭代器类型
  • const_local_iterator        
  • c.begin(n), c.end(n)        桶n的首元素迭代器和尾后迭代器
  • c.cbegin(n), c.cend(n)

哈希策略:

  • c.load_factor()        每个桶的平均元素数量, 返回float值
  • c.max_load_factor() 容器有可能会自动维护平均桶的数量, 但是桶数量<= max_load_factor的值
  • c.rehash(n)        重组存储, 使得bucket_count >=n 且 bucket_count > size/max_load_factor
  • c.reserve(n)        重组存储, 使得容器可以保存n个元素且不必rehash.

无序容器自定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();
}
int main(int argc, char** argv) {
	using SD_multiset = unordered_multiset<Sales_data, decltype(hasher)*, decltype(eqOp)*>;
	SD_multiset bookstore(42, hasher, eqOp);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yutao1131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值