Если вы просто хотите знать, если множества равны, equals
метод на AbstractSet
реализуется примерно, как показано ниже:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return containsAll(c);
}
Обратите внимание, как она оптимизирует общие случаи, когда:
- в два объекта одинаковы
- Другой объект не является комплектом, и
- Размеры двух комплектов - это diff различны.
После этого containsAll(...)
вернется false
как только он находит элемент в другом наборе, который также не в этом наборе. Но если все элементы присутствуют в обоих наборах, им нужно будет проверить их все.
В худшем случае производительность возникает, когда два набора равны, но не одни и те же объекты. Эта стоимость обычно составляет O(N)
или O(NlogN)
в зависимости от реализации this.containsAll(c)
.
И если вы получаете большие и худшие характеристики корпуса, если они велики и отличаются только небольшим процентом элементов.
UPDATE
Если вы готовы инвестировать время в пользовательском наборе реализации, существует подход, который может улучшить «почти такое же» дело.
Идея состоит в том, что вам необходимо предварительно вычислить и кэшировать хэш для всего набора, чтобы вы могли получить текущее значение хэш-кода установки в O(1)
. Затем вы можете сравнить хэш-код для двух наборов как ускорение.
Как вы могли реализовать такой хэш-код? Ну, если множество хэш-код был:
- нуль для пустого множества, а
- XOR из всех элементов hashcodes для непустого множества,
тогда можно дешево обновить кешированный хэш-код набора при каждом добавлении или удалении элемента. В обоих случаях вы просто XOR хэш-код элемента с текущим заданным хэш-кодом.
Конечно, это предполагает, что хэш-коды элементов являются стабильными, а элементы являются членами множеств. Он также предполагает, что функция hashcode элементов классов классов дает хороший разброс. Это связано с тем, что, когда два набора хэш-кодов одинаковы, вам все равно придется вернуться к сравнению всех .
Вы можете принять эту идею немного дальше ... по крайней мере теоретически.
Предположим, что класс заданного элемента имеет метод для возврата контрольных сумм криптограммы для элемента. Теперь реализуем контрольные суммы набора с помощью XORing контрольных сумм, возвращаемых для элементов.
Что это покупает у нас?
Ну, если мы предположим, что ничего не сделано, вероятность того, что любые два неравных множества элемента имеют одни и те же контрольные суммы N-бит, равна 2 -N. А вероятность 2 неравных множеств имеет те же N-битовые контрольные суммы, что и 2 -N. Так что моя идея заключается в том, что вы можете реализовать equals
как:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return checksums.equals(c.checksums);
}
В указанных выше предположениях, это только даст вам неправильный ответ один раз в 2 -N времени. Если вы делаете N достаточно большим (например, 512 бит), вероятность неправильного ответа становится незначительной (например, примерно 10 -150).
Недостатком является то, что вычисление криптограмм для элементов очень дорого, особенно по мере увеличения количества бит. Поэтому вам действительно нужен эффективный механизм для запоминания контрольных сумм. И это может быть проблематично.
Невозможно оптимизировать петли, не зная (и не изменяя) логику сравнения. Не могли бы вы показать больше своего кода? – josefx