Частичный упорядоченный компаратор

Как реализовать java.util.Comparator, который упорядочивает свои элементы в соответствии с отношением частичного заказа?

Например, если задано отношение частичного порядка a ≺ c, b ≺ c; порядок a и b равен undefined.

Поскольку Comparator требует полного упорядочения, элементы ордеров реализации, для которых частичное упорядочение undefined произвольно, но последовательно.

Будет ли следующая работа?

interface Item {
    boolean before(Item other);
}

class ItemPartialOrderComperator implements Comparator<Item> {
    @Override
    public int compare(Item o1, Item o2) {
        if(o1.equals(o2)) {  // Comparator returns 0 if and only if o1 and o2 are equal;
            return 0;
        }
        if(o1.before(o2)) {
            return -1;
        }
        if(o2.before(o1)) {
            return +1;
        }
        return o1.hashCode() - o2.hashCode(); // Arbitrary order on hashcode
    }
}
  • Является ли этот компаратор упорядочивающим транзитивным?
    (Я боюсь, что это не так)
  • Требуется ли Comparators быть транзитивным?
    (при использовании в TreeMap)
  • Как правильно его реализовать?
    (если реализация выше не работает)
    (Hashcodes могут столкнуться, для простоты столкновений пример игнорирует столкновения, см. Ответ Damien B на Наложение полного заказа на все экземпляры * любой * класс в Java для отказоустойчивого упорядочения на хэш-кодах.)

Ответ 1

Проблема заключается в том, что когда у вас есть несравнимые элементы, вам нужно вернуться к чему-то умному, чем сравнивать хэш-коды. Например, учитывая частичный порядок {a < b, c < d}, хэш-коды могли бы удовлетворять h (d) h (b) h (c) h (a), что означает, что a < b < c < d < a ( жирный обозначает привязку по хеш-коду), что вызовет проблемы с TreeMap.

В общем, вам, вероятно, нечего делать, кроме того, что топологически сортировать ключи заранее, поэтому некоторые детали о частичных заказах, которые вам интересны, будут приветствоваться.

Ответ 2

Кажется, это скорее ответ, чем комментарий, поэтому я отправлю его

В документации говорится:

Из контекста непосредственно следует, что фактор является отношением эквивалентности на S и что наложенный порядок является полным порядком на S. "

Итак, нет, компаратору требуется полное упорядочение. Если вы реализуете это с частичным заказом, вы нарушаете контракт на интерфейс.

Даже если это может сработать в каком-то сценарии, вы не должны пытаться решить вашу проблему таким образом, чтобы нарушить контракт интерфейса.

См. этот вопрос о структурах данных, которые соответствуют частичному порядку.

Ответ 3

В любое время, когда я пытался использовать хэш-коды для такого рода вещей, я пришел, чтобы пожалеть об этом. Вы будете намного счастливее, если ваш заказ будет детерминированным - для отладки, если ничего другого. Достигнув этого, создав новый индекс для любого ранее не встречавшегося Item и используя эти индексы для сравнения, если все остальное не получится.

Обратите внимание, что упорядочение по-прежнему не гарантируется транзитивным.

class ItemPartialOrderComperator implements Comparator<Item> {
    @Override
    public int compare(Item o1, Item o2) {
        if(o1.equals(o2)) {
            return 0;
        }
        if(o1.before(o2)) {
            return -1;
        }
        if(o2.before(o1)) {
            return +1;
        }
        return getIndex(o1) - getIndex(o2);
    }

    private int getIndex(Item i) {
        Integer result = indexMap.get(i);
        if (result == null) {
            indexMap.put(i, result = indexMap.size());
        }
        return result;
    }

    private Map<Item,Integer> indexMap = new HashMap<Item, Integer>();
}

Ответ 4

В jdk7 ваш объект будет вызывать исключение во время выполнения:

Область: API: Утилиты     Синопсис: обновленное поведение сортировки для массивов и коллекций может вызвать исключение IllegalArgumentException     Описание: Алгоритм сортировки, используемый java.util.Arrays.sort и (косвенно) на java.util.Collections.sort, был заменен.
реализация нового типа может вызвать исключение IllegalArgumentException, если оно обнаруживает сравнимое, которое нарушает договор Сопоставимости. предыдущая реализация молча игнорировала такую ​​ситуацию.     Если требуется предыдущее поведение, вы можете использовать новое системное свойство java.util.Arrays.useLegacyMergeSort для восстановления предыдущего слияния.

    Характер несовместимости: поведенческий
    RFE: 6804124

Ответ 5

Если a < b и b < c подразумевает a < c, вы сделали полный порядок с помощью хэш-кодов. Возьмите a < d, d < c. Частичный порядок говорит о том, что b и d не обязательно упорядочены. Представляя хэш-коды, вы предоставляете заказ.

Пример: is-a-потомок (человека, человека).

Adam (hash 42) < Moses (hash 17), Adam < Joe (hash 9)

Подразумевается

Adam < Joe < Moses

Отрицательный пример будет тем же самым отношением, но когда путешествие во времени позволяет быть вашим собственным потомком.

Ответ 6

Когда один элемент не является "до" или "после" другого, вместо того, чтобы возвращать сравнение хэш-кода, просто верните 0. Результатом будет "полное упорядочение" и "произвольное" упорядочение совпадающих элементов.