使用 std::sort 进行拓扑排序

Posted

技术标签:

【中文标题】使用 std::sort 进行拓扑排序【英文标题】:Topological sorting using std::sort 【发布时间】:2014-06-18 12:56:37 【问题描述】:

注意:在写这个问题时,我想我已经找到了答案。随意修改或附加更好的版本。我认为记录我的问题可能会很好。 编辑我错了,我的回答不正确。

考虑整数对列表:我想根据部分排序对它们进行拓扑排序。这类似于 Is partial-order, in contrast to total-order, enough to build a heap? ,但我想使用 std::sort 而不是 std::priority_queue。

为此,我编写了这段代码:

#include <iostream>
#include <vector>
#include <algorithm>


struct pair 
    int a, b;
    pair(int a, int b) : a(a), b(b) 

    std::ostream &print(std::ostream &out) const 
        return (out << "(" << a << ", " << b << ")");
    
;

std::ostream &operator<<(std::ostream &out, const pair &p)  return p.print(out); 

struct topological_pair_comparator 
    bool operator()(const pair &p, const pair &q) const  return p.a<q.a && p.b<q.b; 
 tpc;

std::vector<pair> pairs = 
    pair(1,1),
    pair(1,2),
    pair(2,1),
    pair(3,1),
    pair(1,3),
    pair(5,5),
    pair(2,2),
    pair(4,0)
;

int main() 
    std::sort(pairs.begin(), pairs.end(), tpc);
    for(const pair &p : pairs) std::cout << p << " ";
    std::cout << std::endl;
    return 0;

来源:http://ideone.com/CxOVO0

导致:

(1, 1) (1, 2) (2, 1) (3, 1) (1, 3) (2, 2) (4, 0) (5, 5) 

这几乎是拓扑排序的(通过示例证明;)。

但是,根据 tpc,偏序会创建 !((1,2) (2,1)),因此可以得出 ( 1,2) == (2,1)。但是,c++ 标准(2012 年 1 月工作草案)第 25.4.3 段指出:

对于所有采用比较的算法,都有一个使用运算符

已编辑:根据 ecatmur 的有效答案: 偏序不一定是严格的弱序;它打破了不可比性的传递性。所以我想放弃我的推理,即部分排序始终是严格的弱排序和相关问题,并添加问题:我是否注定要自己写拓扑排序算法还是使用需要我构建图的 boost 实现?

解决方案: ecatmur 的聪明建议:

struct topological_pair_comparator 
    bool operator()(const pair &p, const pair &q) const  return (p.a + p.b) < (q.a + q.b); 
 tpc;

来源:http://ideone.com/uoOXNC

请注意,关于堆的 SO 没有明确提到 std::sort 是拓扑排序的;除了一条没有论据支持的评论。

【问题讨论】:

根据***,偏序也不是严格的弱序:en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings。但是,我似乎不知道提到的四个属性中的哪个属性无效。它也没有说明你提到的含义,它只是提到不可比性是一种等价关系。我不太确定,但我找不到不可比性不是等价关系的部分排序的反例。 a 和 b 的不可比性被定义为 not (a :) 我疯了,别管我。 你的假设是错误的。所有严格弱序都是偏序,但并非所有偏序都是严格弱序。严格弱序是具有不可比性传递性的附加属性的偏序。 如果你不知道先验邻接表并且你没有足够的幸运能够将偏序细化为严格的弱序,那么我认为这个问题应该有帮助:***.com/questions/4600258/sorting-a-poset 【参考方案1】:

考虑值

pair
    x0, 1,
    y2, 0,
    z1, 2;

这里,

!tpc(x, y) && !tpc(y, x);
!tpc(y, z) && !tpc(z, y);

然而,

tpc(x, z);

因此,您的比较器强制执行严格的弱排序,如果您将其与std::sort 或任何其他需要严格弱排序的角色一起使用,则行为未定义。

一个 严格弱且是您的比较器改进的比较器将是:

struct refined_comparator 
    bool operator()(const pair &p, const pair &q) const  return p.a + p.b < q.a + q.b; 
 rc;

【讨论】:

我明白了,然后我应该使用什么来进行拓扑排序? :( @Herbert 比较器 p.a + p.b &lt; q.a + q.b 严格弱,是您比较器的改进。 聪明的把戏,谢谢。如果您愿意将其附加到您的答案中,那就太好了!

以上是关于使用 std::sort 进行拓扑排序的主要内容,如果未能解决你的问题,请参考以下文章

拓扑排序 编程

使用 DFS 算法对有向图和无向图进行拓扑排序

拓扑排序算法实现

使用 拓扑排序进行有向无环图 任务关系拆解,实现任务编排

使用 拓扑排序进行有向无环图 任务关系拆解,实现任务编排

『拓扑排序』拓扑排序模板