【发布时间】:2011-01-03 21:28:07
【问题描述】:
我想使用multiset 来计算一些自定义键。键在数字上不可比较,比较两个键没有任何意义,但可以检查它们的相等性。
我看到multiset 模板需要Compare 来订购多重集。顺序对我来说并不重要,重要的是数量。如果我完全省略 Compare 会发生什么?多重设置对我的自定义键没有任何问题吗?如果我不能使用std::multiset,我有什么替代方案?
【问题讨论】:
我想使用multiset 来计算一些自定义键。键在数字上不可比较,比较两个键没有任何意义,但可以检查它们的相等性。
我看到multiset 模板需要Compare 来订购多重集。顺序对我来说并不重要,重要的是数量。如果我完全省略 Compare 会发生什么?多重设置对我的自定义键没有任何问题吗?如果我不能使用std::multiset,我有什么替代方案?
【问题讨论】:
如果您只能比较键是否相等,则不能使用std::multiset。对于关联容器,您的键类型必须具有由比较操作强加的严格弱排序。
严格的弱排序不一定是数字。
[在关联容器中使用时,实际上不需要相等比较。密钥等价由!compare(a, b) && !compare(b, a)确定。]
如果您真的无法为您的键定义排序,那么您唯一的选择是使用键值对的序列容器并使用线性搜索进行查找。不用说,对于类似集合的操作,这将比 multiset 效率低,因此您可能应该尽可能地尝试创建排序。
【讨论】:
std::unordered_multimap 也可能是一种选择。散列函数不必提供排序,只需提供相同键的相同值以及不同键的不同值的合理概率。
如果您没有严格的弱排序,则不能使用std::multiset。您的选择是:
对您的数据实施严格-弱排序。如果您的键是“线性”数据结构,通常最好按字典顺序进行比较。
使用等效的无序容器,例如 boost::unordered_multiset。为此,您需要使您的自定义数据类型可散列,这通常比强加某种顺序更容易。
【讨论】:
unordered_multiset 是我要找的
如果您完全省略 Compare,它将获得默认值,即 less(它给出了应用到您的键的 < 运算符的结果)——它可能会也可能不会为您编译键。
有一个排序的原因是它允许实现通过它们的键更快地查找元素(在插入、删除等时),要理解为什么,想象一下在字典中查找单词。传统字典使用字母顺序,这使得单词易于查找。如果你正在为一种不容易排序的语言准备字典——比如象形语言——那么要么很难在其中找到单词(你必须搜索整个字典),或者你' d 尝试找到一种合乎逻辑的方式来对它们进行排序(例如,将所有可以用笔画的图片放在首位,然后是两条线,等等......) - 因为即使这个顺序是完全任意的,它也会使找到字典中的条目效率更高。
同样,即使您的键不需要为您自己的目的进行排序,并且没有任何自然顺序,您通常也可以定义一个足以解决这些问题的排序。排序必须是可传递的(如果a<b 和b<c 然后a<c),并且严格(对于a<a 从不返回真),不对称(a<b 和b>a 从不同时为真)。理想情况下,它应该对所有元素进行排序(如果a 和b 不同,则a<b 或b<a),尽管你可以摆脱这不是真的(即strict weak ordering) - 虽然这是相当技术性的.
确实,也许它最明显的用途是在极少数情况下完全不可能订购商品 - 在这种情况下,您可以提供一个始终返回 false 的比较运算符。这很可能会导致性能下降,但至少会正常运行。
【讨论】:
所以你列出了两个重要的标准。
一个假设,
multiset 的事实意味着有很多实例那么,为什么不使用std::vector 或std::deque 或std::list?那么您可以利用各种可以使用相等检查的算法(例如count_if 等)
【讨论】:
count_if 算法——这需要一个完整的迭代......