【问题标题】:Multiset without Compare?没有比较的多集?
【发布时间】:2011-01-03 21:28:07
【问题描述】:

我想使用multiset 来计算一些自定义键。键在数字上不可比较,比较两个键没有任何意义,但可以检查它们的相等性。

我看到multiset 模板需要Compare 来订购多重集。顺序对我来说并不重要,重要的是数量。如果我完全省略 Compare 会发生什么?多重设置对我的自定义键没有任何问题吗?如果我不能使用std::multiset,我有什么替代方案?

【问题讨论】:

    标签: c++ templates multiset


    【解决方案1】:

    如果您只能比较键是否相等,则不能使用std::multiset。对于关联容器,您的键类型必须具有由比较操作强加的严格弱排序

    严格的弱排序不一定是数字。

    [在关联容器中使用时,实际上不需要相等比较。密钥等价由!compare(a, b) && !compare(b, a)确定。]

    如果您真的无法为您的键定义排序,那么您唯一的选择是使用键值对的序列容器并使用线性搜索进行查找。不用说,对于类似集合的操作,这将比 multiset 效率低,因此您可能应该尽可能地尝试创建排序。

    【讨论】:

    • 如果您可以使用 C++0x 功能,那么std::unordered_multimap 也可能是一种选择。散列函数不必提供排序,只需提供相同键的相同值以及不同键的不同值的合理概率。
    • @Bart van Ingen Schenau:是的,尽管我发现很难想到在任何情况下都无法获得完整订单的情况下,您可以为这样的散列函数提供合适的输入.
    • 如果您仅将部分键用于散列函数,则您只能获得部分顺序。如果你想反常(并接受可能的性能损失),你可以让哈希函数只返回一个常数。
    • @Bart van Ingen Schenau:我的观点是,在实践中,如果您有输入要提供给散列函数,为什么不直接使用提供给散列的所有字节来确定完整的顺序?我同意理论上可以有一个没有完整顺序的好东西,但它会在实践中发生吗?
    • @Bart:但在这种情况下,您也有完整的订单。他的问题是,您是否可以想出一个可以计算出良好哈希值的情况,而 却无法对数据进行排序。
    【解决方案2】:

    如果您没有严格的弱排序,则不能使用std::multiset。您的选择是:

    1. 对您的数据实施严格-弱排序。如果您的键是“线性”数据结构,通常最好按字典顺序进行比较。

    2. 使用等效的无序容器,例如 boost::unordered_multiset。为此,您需要使您的自定义数据类型可散列,这通常比强加某种顺序更容易。

    【讨论】:

    • unordered_multiset 是我要找的
    【解决方案3】:

    如果您完全省略 Compare,它将获得默认值,即 less(它给出了应用到您的键的 < 运算符的结果)——它可能会也可能不会为您编译键。

    有一个排序的原因是它允许实现通过它们的键更快地查找元素(在插入、删除等时),要理解为什么,想象一下在字典中查找单词。传统字典使用字母顺序,这使得单词易于查找。如果你正在为一种不容易排序的语言准备字典——比如象形语言——那么要么很难在其中找到单词(你必须搜索整个字典),或者你' d 尝试找到一种合乎逻辑的方式来对它们进行排序(例如,将所有可以用笔画的图片放在首位,然后是两条线,等等......) - 因为即使这个顺序是完全任意的,它也会使找到字典中的条目效率更高。

    同样,即使您的键不需要为您自己的目的进行排序,并且没有任何自然顺序,您通常也可以定义一个足以解决这些问题的排序。排序必须是可传递的(如果a<bb<c 然后a<c),并且严格(对于a<a 从不返回真),不对称(a<bb>a 从不同时为真)。理想情况下,它应该对所有元素进行排序(如果ab 不同,则a<bb<a),尽管你可以摆脱这不是真的(即strict weak ordering) - 虽然这是相当技术性的.

    确实,也许它最明显的用途是在极少数情况下完全不可能订购商品 - 在这种情况下,您可以提供一个始终返回 false 的比较运算符。这很可能会导致性能下降,但至少会正常运行。

    【讨论】:

      【解决方案4】:

      所以你列出了两个重要的标准。

      1. 你不在乎订单
      2. 键的比较没有任何意义

      一个假设,

      1. 您使用multiset 的事实意味着有很多实例

      那么,为什么不使用std::vectorstd::dequestd::list?那么您可以利用各种可以使用相等检查的算法(例如count_if 等)

      【讨论】:

      • 如我所说,我需要按键的数量。
      • @nimcap,因此使用了count_if 算法——这需要一个完整的迭代......
      • 我知道,但是在我的情况下单独重建计数会很昂贵
      猜你喜欢
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      • 2019-10-25
      • 2019-01-13
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      相关资源
      最近更新 更多