У меня неправильное представление об интерфейсе Comparator и его методе сравнения вот следующий код, и мне интересно, почему метод сравнения возвращает -33, я считаю, что он должен возвращать 33
import java.util.*;
public class Sorted implements Comparable<Sorted>, Comparator<Sorted> {
private int num;
private String text;
Sorted(int n, String t) {
this.num = n;
this.text = t;
}
public String toString() {
return "" + num;
}
public int compareTo(Sorted s) {
return text.compareTo(s.text);
}
public int compare(Sorted s1, Sorted s2) {
System.out.println(s1.num-s2.num); // return -33
return s1.num - s2.num;
}
public static void main(String[] args) {
Sorted s1 = new Sorted(88, "a");
Sorted s2 = new Sorted(55, "b");
TreeSet<Sorted> t1 = new TreeSet<>();
t1.add(s1); t1.add(s2);
TreeSet<Sorted> t2 = new TreeSet<>(s1);
t2.add(s1); t2.add(s2);
System.out.println(t1 + " " + t2);
System.out.println(s1.num-s2.num); // prints 33
} }
конечно, я согласен с вами. но это то, что я пытаюсь выяснить (как TreeSet сравнивает элемент буксировки)




Вы наверняка знаете, что если a-b=c, то b-a=-c.
То, что здесь происходит, очень похоже. Вы, кажется, предположили, что TreeSet вызывает метод compare следующим образом:
comparator.compare(s1, s2)
(Обратите внимание, что я использовал s1 и s2 в демонстрационных целях. Очевидно, что они не входят в область применения TreeSet. s1 — это тот же экземпляр, что и ваш s1, а s2 — тот же экземпляр, что и ваш s2`.)
Но он может вызывать compare и так:
comparator.compare(s2, s1)
не так ли?
Если он назвал это вторым способом, то следует ожидать результата -33.
Обновлено:
Я просмотрел исходный код TreeSet.add и обнаружил, что он вызывает TreeMap.put с элементом, который вы добавляете в качестве ключа. Если вы посмотрите дальше в TreeMap.put, вы найдете:
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key); // <--- "key" is the key passed into this method
// "t" is an element that is already in the map
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Это показывает, что TreeSet действительно вызывает compare так, как я описал.
Обновлено:
Как сказал Хольгер в комментариях, вы не должны реализовывать Comparator, вычитая два целых числа. Вместо этого вы должны использовать Integer.compare:
return Integer.compare(s1.num, s2.num);
На самом деле нет необходимости реализовывать Comparator вообще, вы можете передать Comparator.comparingInt(s -> s.num) при создании TreeMap:
TreeSet<Sorted> t1 = new TreeSet<>(Comparator.comparingInt(s -> s.num));
я согласен с вами, но в некоторых других программах это называется обычным способом, а не наоборот, откуда я знаю, как Treeset вызывает метод сравнения
@user2780962 user2780962 Вам не нужно это знать, если только вы сами не пытаетесь написать TreeSet. В методе compare ваша единственная задача — сравнить два объекта. Вы не должны зависеть от порядка аргументов. Если вам просто интересно, я добавил часть исходного кода, который показывает, как вызывается compare.
@user2780962 user2780962 Что вам нужно понять, так это то, что вы не могу полагаетесь на любой заказ. Вы должны предоставить хороший компаратор, вот и все.
@ user2780962 Мой ответ ответил на ваш вопрос? Если это так, пожалуйста, примите его, нажав на эту галочку!
Кроме того, вы все равно не должны использовать минус для компаратора. Разница между двумя значениями int может превышать диапазон значений int, следовательно, происходит переполнение. В качестве дополнительного углового случая, когда разница составляет ровно Integer.MIN_VALUE, она будет асимметричной. Правильным решением будет вызов Integer.compare(s1.num, s2.num), однако сомнительно, чтобы этот класс все равно реализовывал Comparator. Используйте new TreeSet<>(Comparator.comparingInt(s -> s.num)), чтобы создать набор, отсортированный по num.
@Holger Вы правы, но это не вопрос ОП, не так ли? Вот почему я не включил его в ответ.
Я думаю, стоит указать на эти вещи, в дополнение к ответу, вместо того, чтобы отпускать ОП, думая, что все их проблемы решены.
@Холгер Хорошо. Отредактировано.
s1 и s2 в compare(Sorted s1, Sorted s2) являются определениями локальных переменных, вы не должны путать их с определениями в main(). Не определено (алгоритмически, только реализацией), как TreeSet сравнивает два элемента.
compare(s1, s2) //yields 33
compare(s2, s1) //yields -33
TreeSet внутренне использует TreeMap. put вызовы сравниваются в нескольких местах, обычно с элементом, который вы помещаете в TreeSet в качестве первого элемента. Поэтому put(s2)позвонит compare(s2, s1). См. фрагмент кода ниже:
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
Другие реализации или методы могут иметь другое поведение.
s1 и s2 в compare(Sorted s1, Sorted s2) являются определениями локальных переменных, вы не должны путать их с определениями в main(). Не определено (алгоритмически, только реализацией), как TreeSet сравнивает два элемента.