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

时间:2014-06-18 12:56:37

标签: c++ sorting c++11 topological-sort

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

考虑整数对列表:我想基于部分排序对它们进行拓扑排序。这与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)&lt;(2,1))和!((1,2)&gt;(2,1)),因此可以结论(1,2)==(2,1)。但是,c ++标准(2012年1月工作草案)第25.4.3段规定:

  

对于所有采用比较的算法,有一个版本使用运算符&lt;代替。那就是comp(* i,   * j)!= false默认为* i&lt; * j!= false。对于除25.4.3中描述的算法之外的算法   正确地说,comp必须对值进行严格的弱排序。

已编辑:根据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在拓扑上排序;除了一条评论,没有论证支持。

1 个答案:

答案 0 :(得分:6)

考虑值

pair
    x{0, 1},
    y{2, 0},
    z{1, 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;