【问题标题】:Sorted set without a strict weak ordering没有严格弱排序的排序集
【发布时间】:2016-02-04 01:07:38
【问题描述】:

我有以下问题:考虑这个(简化的)结构:

struct Task {
    int priority;
    std::string description;
    // Some other fields
};

现在我想要一组所有的任务并用它做一些工作。因此我有一个相等运算符,它检查每个元素是否相等。

bool isEqual(const Task& lhs, const Task& rhs) {
    return lhs.priority == rhs.priority &&
        lhs.description == rhs.description &&
        // Some other fields
        ;
}

为此,我使用了 std::unordered_set,效果很好。

但是现在我希望这些任务按照它们在集合中的优先级(以获得最高优先级的任务)进行排序。显然,这对于 std::unordered_set 是不可能的,所以我尝试了一个带有以下 less 运算符的 std::set:

bool lessTask(const Task& lhs, const Task& rhs) {
    return lhs.priority < rhs.priority;
}

但这意味着通过严格的弱排序,当优先级相等时,两个任务是相等的,这是我不想要的(我想维护我的 isEqual 方法来进行相等性检查)。

完成一组任务的最佳方法是什么,我可以非常快速地插入元素并且没有重复条目(由我的 isEqual 函数定义),但能够非常快速地检索具有最高优先级的任务?
我没有绑定到任何特定的 STL 容器,但不想使用任何第三方库(甚至没有提升)。

【问题讨论】:

  • 我只会做一个比较运算符,先比较优先级,然后再比较其他字段。

标签: c++ c++11 containers strict-weak-ordering


【解决方案1】:

先写get_tie

// auto or decltype(auto)
auto get_tie(const Task& task) {
  return std::tie(lhs.priority, lhs.description, /* some other fields */ );
}

在 C++11 中,您必须使用 -&gt;decltype 尾随返回类型重复主体,或者使用宏来避免重复:

#define RETURNS(...) decltype(__VA_ARGS__) { return __VA_ARGS__; }
auto get_tie(const Task& task)->
RETURNS( std::tie(lhs.priority, lhs.description, /* some other fields */ ) )

一旦我们有一个简单的get_tie,您的问题就会烟消云散。

bool isEqual( Task const& lhs, Task const& rhs ) {
  return get_tie(lhs)==get_tie(rhs);
}
bool isLess( Task const& lhs, Task const& rhs ) {
  return get_tie(lhs) < get_tie(rhs);
}

只需将isLess 传递给std::set,或使用isLess 构建std::vectorstd::sort

现在,如果您的比较不适用于原始的 tie 引用,您可能需要用更复杂的东西替换 get_tie

【讨论】:

    【解决方案2】:

    当你把一个元素放到地图上时,你通常需要将类的所有成员添加到less。否则将无法正常工作。当我必须创建一个包含大约 15 个不同的、不断变化的类的系统时,地图中包含了一个巨大的挑战,而这正是我真正开始怀念编译时反射的时候。

    附带说明,您可以使用 优先队列 (std::make_heap) 来代替地图。优先级堆不关心是否相等,会优先给你最高优先级的任务。

    【讨论】:

    • 优先队列不同;一方面,它们确实需要严格的弱排序。
    • @LightnessRacesinOrbit,不确定我是否关注。如果我对 OP 的理解正确,它将准确地提供所需的功能 - 能够将项目放入容器中,仅根据优先级定义排序并弹出具有最高优先级的项目。为什么你认为它不能解决 OP 的问题?
    • 因为优先级队列需要严格的弱排序。这意味着比较器不能考虑priority 字段。如果确实如此,对容器的操作将具有未定义的行为。幸运的是,std::make_heap 与优先级队列无关,这是我的主要观点。
    • @LightnessRacesinOrbit 堆还需要严格的弱排序比较器(请参阅cplusplus.com/reference/algorithm/make_heap)。但我也没有不重复的保证,这不在此解决方案中。
    • @LightnessRacesinOrbit,std::make_heap 与优先级队列无关是什么意思?它在容器中做一个堆,堆是优先级队列的别称。
    猜你喜欢
    • 2018-08-04
    • 2013-02-14
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    • 2019-06-09
    • 2015-09-20
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多