我们在multiset中有哪些更好的功能不在向量中?

时间:2017-08-03 06:16:07

标签: c++ vector set containers multiset

为什么我们应该使用“多组”(因为我们知道“多组”可以保留重复键)

为什么我们不应该使用vector呢?

我们在向量中没有“多组”中有什么好的功能吗? (或其他容器,如矢量)

你知道“多重套装”有什么特殊用途吗?

1 个答案:

答案 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>>,并且您希望按authortitle对其进行索引以便快速查找。

在这种情况下,您可以为要编制索引的每个字段使用multiset<Book *, CustomComp>;自定义比较器将实现<运算符,该运算符仅考虑指向元素的特定字段。

添加新书时,您只需将其添加到deque和所有索引中;删除图书时,您必须将其从deque和索引中删除。编辑需要首先从索引中删除它,应用更改然后重新添加它(直接修改可能导致multiset实例的状态不一致,因为您可能正在更改存储对象之间的排序关系“在他们背后”)。

这里完全没有一个允许重复元素的集合:它们仅根据比较器重复,它只考虑一个字段;拥有同一作者的多本书或具有相同标题的不同书籍是完全正常的。这里的要点不是“不允许重复”,而是“通过某些键快速查找”,就像我们使用multimap一样,但不必在索引中保留密钥的额外副本。

注释

  1. 当我写?set?map时,我正在谈论“常规”和“多”变体。值得注意的是,讨论的核心主要以相同的方式适用于unordered对应物,将比较器与哈希函数一起更改。
  2. 当然,在进行查找时,您必须提供一个虚拟second参数,这就是使用map更方便的原因。