当"相等"时如何写一个传递比较器?暗示"顺序并不重要"?

时间:2015-01-22 21:48:40

标签: java sorting comparator transitivity

我有一组序列化为文件的项目。某些项目可以依赖其他项目,但不允许循环引用。因此,需要对它们进行序列化,以便A依赖于BB首先在文件中序列化。

我写了Comparator我使用reliesOn()函数确定是否有两个项链接在一起:

Collections.sort(itemsToSort, new Comparator<Item>() {
    @Override
    public int compare(Item first, Item second) {
        boolean firstReliesOnSecond = reliesOn(first, second);
        if (firstReliesOnSecond) {
            return 1;
        }
        boolean secondReliesOnFirst = reliesOn(second, first);
        if (secondReliesOnFirst) {
            return -1;
        }
        return 0;
    }
});

这适用于一些个案,但不是全部。在调试中,很明显排序依赖于Comparator的传递性质,并且可以理解的是并不比较每个可能的项目配对。

例如,有五个项AE,如果:

A -> B
B -> E
C
D
E

然后一个可能的顺序是:

E, B, A, C, D

至少,E出现在B之前,B出现在A之前。

然而,在比较阶段(以释义为例),会发生CE进行比较,返回0因为它们没有关系。然后将CB进行比较,并返回0

结果,排序算法假设B = E的情况。 (即使我违反了Comparator合同。)如何以确保传递性的方式编写compare()方法?

编辑:有人指出我正在对有向无环图执行拓扑排序。我在我的数据结构课程中有闪回。幸运的是,维基百科似乎有一个很好的线性时间算法来执行这种操作 - 我会给它一个机会。

2 个答案:

答案 0 :(得分:2)

  

如何以确保传递性的方式编写compare()方法?

当你发现Comparator的合同迫使你根据两个给定的对象做出决定时,他们在整体排序中的关系可能涉及其他对象。

你在这里有一个DAG,你正在尝试做的是拓扑排序。我认为可以使用Comparator的唯一方法是首先进行拓扑排序,然后在实现比较器时使用此排序中的对象索引作为键。但当然,由于你已经对元素进行了排序,因此不需要比较器。

答案 1 :(得分:0)

违反Comparator的合同对你没什么帮助,因为标准排序算法假设你尊重它。

除了从维基百科实现拓扑排序算法之外,您还可以查看this lib(当有人谈到有向图和拓扑排序时会经常提及)或that实现。