c++primer Chapter 11 Associative Containers

Chapter 11 Associative Containers

  • Associative container elements are stored and accessed by key
  • Sequential container The position in the container to store and access sequentially
     
  • associative container
    • map key-value (key-value)
      • Keyword: the role of the index
      • Value: the data associated with the index
    • set contains only one keyword per element
      • Efficient Keyword Indexing
Table 11.1 Associative Container Types
Save elements in order by key In the header file map and set
map key array: save 关键字-值pairs
set The keyword is the value, that is, the container that only holds the keyword
multimap Keyword can repeatmap
multiset Keyword can repeatset
unordered collection In the header files unordered_map and unordered_set
unordered_map Organized using a hash functionmap
unordered_set Organized using a hash functionset
unordered_multimap Hash-organized map, keywords can appear repeatedly
unordered_multiset Hash-organized set, keywords can appear repeatedly

11.1 Using associative containers

  • map associative array
    • subscript keyword
  • set keyword simple set
    • Used to determine whether a value exists
       
  • use map
    • word count program
      1. The template specifies the type of keywords and values
      1. If the key is not in the map, the subscript operator creates a new element
      1. The map uses the first member of the pair to save the keyword, and uses the second member to save the corresponding value
  • use set
    • Save the words you want to ignore
      1. specify element type
      1. list initialization
      1. if checks whether the word is found in the ignore set (there is an iterator pointing to the keyword, and there is no iterator after the end)

11.2 Overview of associative containers

  • Support for common container operations
  • Sequential container position-related operations (such as push_front/push_back) are not supported
  • Iterators for associative containers are bidirectional

11.2.1 Defining associative containers

  • When defining a map, specify the keyword type and value type
  • When defining a set, specify the keyword type
  • Associative container initialization
    • a copy of another container of the same type
    • A range of values ​​(values ​​convertible to the type required by the container)
    • value initialization { curly braces }
      • set object={variable,variable,variable}
      • map<keytype,valuetype> object={ {key,value},{key,value},{key,value}}
  • Initialize multimap or multiset
    • map/set keywords must be unique
    • multimap/multiset allows multiple elements to have the same key

11.2.2 Keyword Type Requirements

  • Ordered container map/multimap/set/multiset

    • A method for element (keyword type) comparison must be defined<
  • key type for sorted containers

    • Custom actions can be provided in place of the keyword < operator
    • strict weak ordering (less than or equal to)
        1. Two keywords cannot be less than or equal to each other at the same time
        1. If k1<=k2&&k2<=k3, then k1<=k3
        1. Neither of the two keywords is less than or equal to the other, then the two keywords are equivalent (equal)
  • Comparison functions using keyword types

    • This operation type is provided when a custom operation defines an associated container type <given in angle brackets followed by the element type>
    • Two types must be provided <keyword type, comparison operation type>
      • keyword type
      • Comparison operation type (function pointer type)
      • The constructor parameter is passed to the sorting function pointer

11.2.3 pair type

  • Two type names must be provided when creating a pair object
  • Default constructor value-initializes data members; initializers can also be provided for each member
  • Pair has two public data members, first and second
Table 11.2 Operations on pairs
pair<T1, T2> p; pis one pair, and both members of type T1and T2are value-initialized
pair<T1, T2> p(v1, v2); pT1is a pair whose member types are and respectively T2; firstand are initialized with and secondrespectively .v1v2
pair<T1, T2>p = {v1, v2}; Equivalent to `p(v1, v2)
make_pair(v1, v2); Returns a pair initialized with v1 and a binary, pairthe type of which is inferred from the type of the v1sumv2
p.first The returned (public) data member pnamedfirst
p.second The returned (public) data member pnamedsecond
p1 relop p2 Operation relational operators (<, >, <=, >=) are defined in lexicographical order: the first of p1 is less than p2 (or if the first of p1 is not greater than p2, the second of p1 is less than p2), p1<p2 is true , the relational operator is implemented using the == operator of the < operator of the element
p1 == p2 Two pairs are equal when the first and second members are respectively equal. The equality judgment is realized by the == operator of the element
p1 != p2 not equal
  • Function to create a pair object
    • function returns pair
      • The return value can be list-initialized {initializer surrounded by curly braces}
      • Or make an implicitly constructed return value
      • Show constructor return value
      • Use make_pair to generate pair objects

11.3 Associative container operations

Table 11.3 Additional type aliases for associative containers
key_type the keyword type for this container type
mapped_type Types associated with each keyword: Only available formap
value_type For set, key_typethe same as; for map, for pair<const key_type, mapped_type>;
  • Since the keyword of an element cannot be modified, the keyword part of the pair is const
  • Use the scope operator to extract members of a typemap<string,int>::key_type
  • Only the map type (unordered_map/unodered_multimap/multimap/map) defines mapped_type

11.3.1 Associative Containers

  • When dereferencing an associative container iterator, you get a reference to a value of type value_type of the container type
    • for map_pair<const key_type, mapped_type>
    • The first saves the const keyword, and the second member saves the value
    • The value of the pair can be changed, but the value of the keyword member cannot be changed
  • The iterator of set is const, which is the value of the read-only element and cannot be modified
  • traverse associative containers
    • Both map and set support begin and end operations, which can be used to traverse the container
    • Iterator traverses elements in ascending order by key
  • Associative Containers and Algorithms
    • A keyword const means that an associative container cannot be passed to an algorithm that modifies or rearranges the elements of the container
    • Associative containers can be used for algorithms that only read elements
      • Treat an associative container as a source sequence or a destination

11.3.2 Adding elements

  • Inserting an existing element has no effect on the container

  • For a given keyword only the first element with this keyword is inserted into the container

    • insert(v.cbegin(),v.cend());//Accept a pair of iterators
    • insert({1,2,3});//Accept an initializer list
  • Add elements to the map

    • The element type of insert operation is 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_t>::value_type (word, 1));
Table 11.4 Associative container insertoperations
c.insert(v) c.emplace(args) vis value_typean object of type; argsused to construct an element. For mapand , elements are inserted (or constructed) setonly if the element's key is not in . cThe function returns pairan iterator containing an iterator pointing to the element with the specified key, and a boolvalue indicating whether the insertion was successful. For multimapand multisetinserts (or constructs) the given element and returns an iterator pointing to the new element
c.insert(b, e) c.insert(il) band eis an iterator representing a c::value_typerange of values ​​of a type; ilis a curly-brace-listed list of such values. function returns void. For mapand set, only celements whose key is not in are inserted. For multimap and multiset, each element in the range is inserted
c.insert(p, v) c.emplace(p, args) Similar insert(v)(or emplace(args)), but takes the iterator pas a hint as to where to start searching for where new elements should be stored. Returns an iterator pointing to elements with the given key.
  • Check the return value of insert
    • 返回一个pair,first为一个指向具有给定关键字的迭代器,second为判断bool(当元素成功插入返回true,若关键字已存在则insert什么也不做bool返回false)
  • 展开递增语句
++ret.first->second;//等价于
++((rect.first)->second);
  • 向multiset或multimap添加元素
    • multi容器中的关键字不必唯一,调用insert总会插入一个元素

11.3.3 删除元素

  • 关联容器定义了三个版本的erase
    • 接受一个迭代器 删除一个元素
    • 接受一对迭代器 删除一个元素范围
    • 接受一个key_type参数 删除所有匹配关键字的元素
      • 返回实际删除元素的数量
      • 对于multi容器返回值可能大于1,其他容器返回值总为0或1
表11.5 从关联容器删除元素
c.erase(k) c中删除每个关键字为k的元素。返回一个size_type值,指出删除的元素的数量
c.erase(p) c中删除迭代器p指定的元素。p必须指向c中一个真实元素,不能等于c.end()。返回一个指向p之后元素的迭代器,若p指向c中的尾元素,则返回c.end()
c.erase(b, e) 删除迭代器对be所表示范围中的元素。返回e

11.3.4 map的下标操作

  • map和unordered_map容器提供了下标运算符和对应的at函数
  • set不支持下标,因为没有与关键字对应的值
  • multimap和unordered_multimap也不能进行下标操作。因为一个关键字可能对应多个值
map和unordered_map的下标操作
c[k] 返回关键字为k的元素;如果k不在c中,添加一个关键字为k的元素,对其进行值初始化
c.at(k) 访问关键字为k的元素,带参数检查;若k不存在在c中,抛出一个out_of_range异常
  • 使用下标操作的返回值
    • 对map进行下标操作返回一个mapped_type对象(左值)
    • 解引用一个map迭代器时,会得到一个value_type对象
  • 若关键字未在map中,下标运算符会添加一个新元素

11.3.5 访问元素

  • 关联容器 查找指定元素的方法
    • 一个特定元素是否存在于容器中 find
    • 统计有多少个元素有相同关键字 count
表11.7 在一个关联容器中查找元素的操作
lower_bound和upper_bound不适用于无序容器
下标和at操作只适用于非const的map和unordered_map
c.find(k) 返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回尾后迭代器
c.count(k) 返回关键字等于k的元素的数量。对于不允许重复关键字的容器,返回值永远是0或1
c.lower_bound(k) 返回一个迭代器,指向第一个关键字不小于k的元素
c.upper_bound(k) 返回一个迭代器,指向第一个关键字大于k的元素
c.equal_range(k) 返回一个迭代器pair,表示关键字等于k的元素的范围。若k不存在,pair的两个成员均等于c.end()
  • 对map使用find代替下标操作

    • 如果关键字还未在map中,下标操作会插入一个具有给定关键字的元素
  • multimap或multiset中查找元素

    • multimap/multiset中多个元素具有给定关键字,则元素在容器中相邻存储
    • 可利用find找到第一个关键字的迭代器位置,使用count获取容器中该关键字的个数,设为循环次数对迭代器进行递增,即可获取该关键字所对应的所有值
  • 一种不同的,面向迭代器的解决方法

    • 关键字在容器中 lower_bound返回的迭代器将指向第一个具有给定关键字的元素,upper_bound返回的迭代器将指向最后一个匹配给定关键字的元素之后的位置;
    • 关键字的元素不在multimap中,lower_boundupper_bound返回相等的迭代器,指向一个不影响排序的关键字插入位置
    • lower_boundupper_bound之间的迭代器范围,表示具有该关键字的元素的范围(可用for遍历);如果lower_boundupper_bound返回相同的迭代器则给定关键字不在容器中
    • 若查找的元素具有容器中最大的关键字,则关键字的upper_bound返回尾后迭代器;若关键字不存在且大于容器中任何关键字,则lower_boundupper_bound都返回尾后迭代器
  • equal_range函数

    • 函数接受一个关键字,返回一个迭代器pair
    • 若关键字存在,第一个迭代器指向第一个与关键字匹配的元素,即pos.first等价于beg;第二个关键字指向最后一个匹配元素之后的位置,即pos.second等价于end
    • 若未找到匹配元素,则两个迭代器都指向关键字可以插入的位置

11.3.6 一个单侧转换的map

  • map的创建、搜索以及遍历

      1. 程序输入两个文件
        1. 第一个文件保存 string单词转换规则
        1. 第二个文件保存需被替换部分的文本
  • 单词转换程序

    • word_transform 管理整个过程 接受两个ifstream参数(两个文件)
    • buildMap 读取转换规则,创建一个map,保存每个单词到其转换内容的映射
    • transform 接受一个string,若存在转换规则,返回转换后的内容
  • 建立转换映射

    • >>读取要转换的单词存入key中
    • getline读取该行剩余内容为要被转换成的文本
    • 隐含忽略了一个单词在转换文件中出现多次的情况(若存在单词出现多次,则将最后一个对应短语存入trans_map)
  • 生成转换文本

    • find来确定给定string是否在map中
      • 若存在,返回一个指向对应元素的迭代器,解引用迭代器,获得一个保存关键字和值的pair
      • 若不存在,返回尾后迭代器

11.4 无序容器

  • 4个无序关联容器,使用哈希函数和关键字类型的==运算符(而不是比较运算符)来组织元素
  • 关键字类型没有明显序关系
  • 无序容器通常更为简单也会有更好的性能
  • 使用无序容器
    • 哈希管理操作
    • 无序容器也有与有序容器相同的操作
  • 管理桶
    • 无序容器使用一个哈希函数将元素映射到桶
    • 访问一个元素,需先计算元素的哈希值
    • 容器将具有一个特定哈希值的所有元素都保存在相同的桶中
    • 若容器允许重复关键字,则具有相同关键字的元素也都会在同一个桶中
    • 无需容器性能
      • 哈希函数的质量
      • 桶的数量和大小
    • 对相同参数,哈希函数总是产生相同结果;理想情况下,每个特定值映射到唯一的桶;将不同的关键字的元素映射到相同的桶也是允许的
    • 当一个桶保存多个元素时,需要顺序搜索这些元素来查找想要的那个
    • 下表管理桶的成员函数允许我们查询容器的状态以及在必要时强制容器进行重组
表11.8 无序容器管理操作
桶接口
c.bucket_count() 正在使用的桶的数目
c.max_bucket_count() 容器能容纳的最多的桶的数目
c.bucket_size(n) n个桶中有多少个元素
c.bucket(k) 关键字为k的元素在哪个桶中
桶迭代
local_iterator 可以用来访问桶中元素的迭代器类型
const_local_iterator 桶迭代器的const版本
c.begin(n)c.end(n) n的首元素迭代器和尾后迭代器
c.cbegin(n)c.cend(n) 与前两个函数类似,但返回const_local_iterator
哈希策略
c.load_factor() 每个桶的平均元素数量,返回float值。
c.max_load_factor() c试图维护的平均桶大小,返回float值。c会在需要时添加新的桶,使得load_factor<=max_load_factor
c.rehash(n) 重组存储,使得bucket_count>=n,且bucket_count>size/max_load_factor
c.reverse(n) 重组存储,使得c可以保存n个元素且不必rehash
  • 无序容器对关键字类型的要求
    • 无序容器使用关键字类型的==运算符来比较元素
    • 使用一个hash<key_type>类型对象来生成每个元素的哈希值
    • 标准库为内置类型(包括指针)提供了hash模板,为一些标准库类型(如string/智能指针)定义了hash。故可直接定义关键字为这些类型的无序容器
    • 不能直接定义关键字类型为自定义类类型的无序容器,不能直接使用哈希模板,必须提供自己的hash模板版本
    • 不使用默认的hash,使用类似于为有序容器重载关键字类型的默认比较操作(需提供函数来替代==运算符和哈希计算函数)
//使用标准库hash类型(建立在string类型之上)对象来计算isbn成员哈希值
size_t hasher(const sales_datas &sd)
{
    
    
  return hash<string>()(sd.isbn());
}
//通过比较isbn号来比较两个sales_data
bool eqOp(const sales_data &lhs,const sales_data &rhs)
{
    
    
  return lhs.isbn()==rhs.isbn();
}
//定义类型别名 哈希和相等性判断操作
using sd_multiset=unordered_multiset<sales_data,decltype(hasher)*,decltype(eqop)*>;
//使用上述函数定义一个无序容器 参数为 桶大小,哈希函数指针和相等性判断运算符指针
sd_multiset bookstore(42,hasher,eqOp);

小结

  • 顺序容器
    • 通过位置访问元素
  • 关联容器
    • 关键字高效查找 提取元素
    • 允许重复关键字的容器都包含multi
    • 无论有序/无序容器中,具有相同关键字的元素都是相邻存储的
  • 有序关联容器
    • 使用比较函数(默认为关键字类型的<运算符)来比较关键字,将元素顺序存储
  • 无序关联容器(unordered)
    • 使用关键字类型==运算符和一个hash<key_type>类型的对象来组织元素

术语表

  • 哈希函数 将给定类型的值映射到整型(size_t)值的函数。相等的值必须映射到相同的整数;不相等的值尽可能映射到不同的整数
  • key_type 保存和提取关键字的类型
  • mapped_type 映射类型定义的类型,就是映射中关键字关联的值的类型
  • value_type 容器中元素的类型
  • 严格弱序 可以比较任意两个值并确定哪个更小,若任何一个都不小于另一个,则认为两个值相等

Guess you like

Origin blog.csdn.net/m0_68312479/article/details/129920841