Java comparator: violation of general contracting

So I have this comparator:

import java.util.Comparator;

public class SolutionComparator implements Comparator<ExpressionTree> {
    private final int target;

    public SolutionComparator(int target) {
        this.target = target;
    }

    @Override
    public int compare(ExpressionTree o1,ExpressionTree o2) {
        int v1 = o1.getValue();
        int v2 = o2.getValue();
        if (v1 == -1 && v2 == -1)
            return 0;
        else if (v1 == -1)
            return 1;
        else if (v2 == -1)
            return -1;
        else if (v1 == v2)
            return (int)Math.signum(solutionCost(o1) - solutionCost(o2));
        else
            return (int)Math.signum(Math.abs(target-v1) - Math.abs(target-v2));
    }

    private int solutionCost(ExpressionTree v) {
        int cost = 0;
        Operation o = v.getOperator();
        if (o != Operation.NONE) {
            cost += o.getCost();
            for (ExpressionTree e : v.getChildren())
                cost += solutionCost(e);
        }
        return cost;
    }
}

I've been looking at this code for months, and I can't find out why it violates the total contract of the comparator

The idea is that each expressiontree can be evaluated as a result (getValue () method) If it returns - 1, it is always higher than other numbers If the value is different, compare its proximity to the target If the values are the same, compare by solution cost

Using this comparator, Java throws illegalstatesexception But if I delete the cost - based comparison, it works

Editing: exception tracking

Exception in thread "Thread-3" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeHi(TimSort.java:868)
    at java.util.TimSort.mergeAt(TimSort.java:485)
    at java.util.TimSort.mergeCollapse(TimSort.java:408)
    at java.util.TimSort.sort(TimSort.java:214)
    at java.util.TimSort.sort(TimSort.java:173)
    at java.util.Arrays.sort(Arrays.java:659)
    at java.util.Collections.sort(Collections.java:217)
    at ***.run(***:123)
    at java.lang.Thread.run(Thread.java:722)

Solution

Your comparator violated the equal transitivity required by the contract:

Suppose you have three expressiontrees O1, O2, O3, V1, V2, V3 and solution costs S1, S2, S3 with corresponding values, such as V1 = = V2, target – V1 = = V3 – target (so ABS (target-v1) = = ABS (target-v3)) and S1 < S2 (so comparison (O1, O2) = = - 1. For simplicity, you can say O1 then O1 = = O3 and O2 = = O3 but O1 < O2, that is, comparison (O1, O3) = = 0 but SGN (comparison (O1, O2))= Since SGN (compare (O3, O2)), SGN (compare (O1, O2)) = - 1 and SGN (compare (O3, O2)) = = 0

I'm not sure how you will solve this problem, but that's why

Editor: @ nat (OP) proposed this elegant solution:

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>