我们在向量中没有的多集中有什么更好的特征?
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 本书,您希望通过 author
和 title
对它们进行索引以便快速查找。
在这种情况下,您可以为每个要索引的字段使用一个multiset<Book *, CustomComp>
;自定义比较器将实现一个 <
运算符,它只考虑指向元素的特定字段。
添加新书时,您只需将其添加到 deque
和所有索引;删除一本书时,您必须将其从 deque
和索引中删除。编辑需要首先从索引中删除它,应用更改,然后 re-add 它(直接修改可能导致 multiset
实例的不一致状态,因为您可能正在更改之间的排序关系存储 objects "behind their back").
这里非常好,您有一个允许重复元素的集合:它们是重复的仅根据比较器,它只考虑一个字段;拥有同一作者的多本书或具有相同标题的不同书籍是完全正常的。这里的要点不是 "not allowing duplicates",而是 "fast lookup by some key",就像我们使用 multimap
一样,但不必在索引中保留额外的密钥副本。
备注
- 当我写
?set
或 ?map
时,我指的是 "regular" 和 "multi" 变体。值得注意的是,讨论的核心主要以相同的方式适用于 unordered
对应物,用散列函数更改比较器。
- 当然,在进行查找时,您必须提供一个虚拟
second
参数,这就是为什么使用 map
更方便。
为什么我们应该使用"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 本书,您希望通过 author
和 title
对它们进行索引以便快速查找。
在这种情况下,您可以为每个要索引的字段使用一个multiset<Book *, CustomComp>
;自定义比较器将实现一个 <
运算符,它只考虑指向元素的特定字段。
添加新书时,您只需将其添加到 deque
和所有索引;删除一本书时,您必须将其从 deque
和索引中删除。编辑需要首先从索引中删除它,应用更改,然后 re-add 它(直接修改可能导致 multiset
实例的不一致状态,因为您可能正在更改之间的排序关系存储 objects "behind their back").
这里非常好,您有一个允许重复元素的集合:它们是重复的仅根据比较器,它只考虑一个字段;拥有同一作者的多本书或具有相同标题的不同书籍是完全正常的。这里的要点不是 "not allowing duplicates",而是 "fast lookup by some key",就像我们使用 multimap
一样,但不必在索引中保留额外的密钥副本。
备注
- 当我写
?set
或?map
时,我指的是 "regular" 和 "multi" 变体。值得注意的是,讨论的核心主要以相同的方式适用于unordered
对应物,用散列函数更改比较器。 - 当然,在进行查找时,您必须提供一个虚拟
second
参数,这就是为什么使用map
更方便。