我们在向量中没有的多集中有什么更好的特征?

what is the better feature do we have in multiset that is not in vector?

为什么我们应该使用"multi set"(因为我们知道"multi set"可以保持重复键)

为什么我们不应该改用向量?

"multi set" 中是否有任何我们在 vector 中没有的好的特征? (或其他容器,如矢量)

你知道 "multi set" 的特殊用法吗?

(moving/expanding 来自评论)

what is the better feature do we have in multiset that is not in vector?

关键特性是快速 (O(log N)) 查找 "equivalent"(根据比较器)元素,加上根据比较器的隐式排序(插入成本为 O(log N)) .

(加上通常的 set 特性,例如 O(1) 删除(在 O(log N) 搜索之后)和永不失效的引用)


multiset 是一个很好的 "niche" 容器;在 10 多年的 C++ 编写过程中,我认为我从未使用过它(或看到它被使用过,FWIW)。很可能,它的存在很大程度上归功于 map/set <=> multimap/multiset 对称性。

set 通常被认为是 "the container which does not allow duplicate elements",因此拥有一个允许重复的集合显然毫无意义。然而,set 的实际要点是允许根据某些标准 快速(O(log n))查找 objects ,这可能不会考虑完整 object 的内容。

让我们退一步;在这里理解 ?map 只是伪装成 1?set 会很有帮助。特别是,您可以将 std::?map<K,V> 视为 std::?set<pair<const K,V>,KeyComp>,其中 KeyComp 是仅考虑对 [=77] 的 first(=key)部分的比较器=]2 - 顺便说一句 is exactly what std::?map::value_compare 是;您还会注意到 std::?map::value_type 的类型确实是 std::pair<const K, V>.

因此,?map 本质上比 ?set 更方便,适用于您希望通过某个尚未 "inside the value itself".

的键索引值的常见情况

相反,如果键已经存储在值中 - 这通常是我们通过其某些属性索引现有数据时发生的情况 - 可以使用带有自定义比较器的 ?set,从而避免?map.

中所需的密钥的密钥复制

让我们考虑一个假想的图书数据库;您有一个很大的 std::deque<std::unique_ptr<Book>>,其中包含所有 object 本书,您希望通过 authortitle 对它们进行索引以便快速查找。

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

添加新书时,您只需将其添加到 deque 和所有索引;删除一本书时,您必须将其从 deque 和索引中删除。编辑需要首先从索引中删除它,应用更改,然后 re-add 它(直接修改可能导致 multiset 实例的不一致状态,因为您可能正在更改之间的排序关系存储 objects "behind their back").

这里非常好,您有一个允许重复元素的集合:它们是重复的仅根据比较器,它只考虑一个字段;拥有同一作者的多本书或具有相同标题的不同书籍是完全正常的。这里的要点不是 "not allowing duplicates",而是 "fast lookup by some key",就像我们使用 multimap 一样,但不必在索引中保留额外的密钥副本。


备注

  1. 当我写 ?set?map 时,我指的是 "regular" 和 "multi" 变体。值得注意的是,讨论的核心主要以相同的方式适用于 unordered 对应物,用散列函数更改比较器。
  2. 当然,在进行查找时,您必须提供一个虚拟 second 参数,这就是为什么使用 map 更方便。