为什么我们应该使用“多组”(因为我们知道“多组”可以保留重复键)
为什么我们不应该使用vector呢?
我们在向量中没有“多组”中有什么好的功能吗? (或其他容器,如矢量)
你知道“多重套装”有什么特殊用途吗?
答案 0 :(得分:5)
(从评论中移动/扩展)
我们在multiset中有哪个更好的功能是不在向量中?
关键特性是快速(O(log N))查找“等效”(根据比较器)元素,加上根据比较器的隐式排序(插入时的O(log N)成本))。
(这加上通常的set
功能,例如O(1)删除(在O(log N)搜索之后)和从未失效的引用)
multiset
是一个非常“利基”的容器;在编写C ++ 10多年后,我认为我从未使用它(或者看到它被使用,FWIW)。最有可能的是,它的存在很大程度上归功于map
/ set
< => multimap
/ multiset
对称。
set
通常被认为是“不允许重复元素的容器”,因此拥有一个允许重复的集合显然毫无意义。但是,set
的实际点是允许根据某些标准快速(O(log n))查找对象,这关键可能不会考虑完成对象的内容。
让我们退后一步;这有助于理解?map
只是伪装 1 中的?set
。特别是,您可以将std::?map<K,V>
视为std::?set<pair<const K,V>,KeyComp>
,其中KeyComp
是仅考虑货币对的first
(=键)部分的比较器 2 - 偶然is exactly what std::?map::value_compare
;您还会注意到std::?map::value_type
的类型确实是std::pair<const K, V>
。
因此,对于您希望通过某些尚未“在值本身内部”的键索引值的常见情况,?map
基本上比?set
更方便。
如果密钥已经存储在值中 - 这通常是我们通过某些属性索引现有数据时会发生的情况 - 可以使用带有自定义比较器的?set
,从而避免密钥复制?map
中需要的密钥。
让我们考虑一个虚构的图书数据库;您有一个包含所有图书对象的大std::deque<std::unique_ptr<Book>>
,并且您希望按author
和title
对其进行索引以便快速查找。
在这种情况下,您可以为要编制索引的每个字段使用multiset<Book *, CustomComp>
;自定义比较器将实现<
运算符,该运算符仅考虑指向元素的特定字段。
添加新书时,您只需将其添加到deque
和所有索引中;删除图书时,您必须将其从deque
和索引中删除。编辑需要首先从索引中删除它,应用更改然后重新添加它(直接修改可能导致multiset
实例的状态不一致,因为您可能正在更改存储对象之间的排序关系“在他们背后”)。
这里完全没有一个允许重复元素的集合:它们仅根据比较器重复,它只考虑一个字段;拥有同一作者的多本书或具有相同标题的不同书籍是完全正常的。这里的要点不是“不允许重复”,而是“通过某些键快速查找”,就像我们使用multimap
一样,但不必在索引中保留密钥的额外副本。
?set
或?map
时,我正在谈论“常规”和“多”变体。值得注意的是,讨论的核心主要以相同的方式适用于unordered
对应物,将比较器与哈希函数一起更改。second
参数,这就是使用map
更方便的原因。