Как заставить метод сравнения соблюдать общий договор?

Хромосома содержит ряд баллов, сгенерированных разными способами. Метод compareTo фактически проверяет соответствие методов и, соответственно, возвращает результат.

возврат 1: комп = -5..- 1

return 0: comp = 0 (может случиться в разных сценариях, один из которых состоит в том, что все оценки равны.

возврат -1: комп = 1..5

public int compareTo(Chromosome o) {
    if(o == null)
        return(1);
    int comp = 0;
    comp += Double.compare(getScore(1),o.getScore(1));
    comp += Double.compare(getScore(2),o.getScore(2));
    comp += Double.compare(getScore(3),o.getScore(3));
    comp += Double.compare(getScore(5),o.getScore(5));
    comp += Double.compare(getScore(7),o.getScore(7));
    if(comp == 0)
        return(0);
    if(comp > 0)
        return(1);
    else
        return(-1);
}

У меня вопрос, как заставить этот сценарий придерживаться правил, налагаемых контрактом для компаратора. Очевидно это не так, и я продолжаю получать: java.lang.IllegalArgumentException: метод сравнения нарушает его общий контракт!

3 ответа

Чтобы немного уточнить ответ сэра Ротна:

compareTo Метод должен придерживаться двух свойств:

  • Сравнение симметрично, т. Е. Если A=B затем B=A и если A<B затем B>A
  • Сравнение транзитивно, т. Е. Если A<B а также B<C затем A<C, и если A=B а также B=C затем A=C

Первое свойство встречается для сравнения, а второе - нет. Рассмотрим следующий пример из теории голосования: у нас есть 3 человека, которые голосуют за 3 варианта. Побеждает альтернатива с самым высоким рейтингом. Известно, что это может привести к неоднозначной ситуации, когда нет альтернативы.


В вашем случае оценки - это люди, а хромосомы - альтернативы. Вместо 5 баллов я использую только 3, так как этого достаточно, чтобы показать проблему. У меня есть 3 хромосомы, A, B, а также Cсо счетами следующим образом:

A: 1, 2, 3
B: 2, 3, 1
C: 3, 1, 2

Нетрудно понять, что A<B, B<Cи C<Aтак что ваше сравнение не является переходным.


Вы можете решить эту проблему, упорядочив хромосомы лексикографически:

public int compareTo(Chromosome o) {
    if(o == null)
        return(1);
    int[] indices = {1, 2, 3, 5, 7};
    for (int i : indices) {
        int c = Double.compare(getScore(i),o.getScore(i));
        if (c != 0)
            return c;
    }
    return 0;
}

Если вы реализуете интерфейс Comparator, то вам нужно использовать этот метод (учитывая, что ваш класс является общим для tpye Chromosome):

int compare(Chromosome o1, Chromosome o2)

Тем не менее, кажется, что более подходящим интерфейсом для реализации в вашем случае является Comparable. http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

int compareTo(Chromosome o)

Comparable обычно реализуется, чтобы дать экземплярам вашего класса естественный порядок. Comparator, как правило, является отдельным классом того, что вы пытаетесь сравнить, и может использоваться для предоставления вам нескольких различных типов заказов.

Независимо от того, что вы реализуете, класс также должен быть напечатан:

class Chromosome implements Comparable<Chromosome> 

В противном случае аргументы должны быть Object, а не Chromosome.

Кажется, что вы пытаетесь реализовать, что одна хромосома больше другой, если у нее больше баллов, чем у другой. К сожалению, это не обеспечивает четкого приоритета. Т.е. вы не можете гарантировать, что каждое из o1 = o2 и o2 = o3 o1 = o3 верно. Это может привести к бесконечному циклу упорядочения или, используя более продвинутый алгоритм, исключений, с которыми вы сталкиваетесь. Поэтому вам нужно найти другой алгоритм, обеспечивающий стабильную сортировку.

Подходы:

  1. Сравните сумму баллов
  2. Определите приоритет оценки (оценка 2 сравнивается, только если оценка равна 1 и т. Д.)
Другие вопросы по тегам