HashSet против ArrayList

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

public class Class {
    private Set<Student> students;

    // other methods
}

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

вопрос: какую структуру данных я должен использовать для наилучшей реализации этого? Поскольку я буду изменять свойство объектов Student в set student (тем самым изменяя хэш-коды) должен ли я использовать ArrayList вместо этого?

9 ответов


какую структуру данных я должен использовать для наилучшей реализации этого? Поскольку я буду изменять свойство объектов Student в set student (тем самым изменяя хэш-коды), должен ли я использовать ArrayList вместо этого?

если хэш-коды для элементов набора могут измениться, то вы не должны использовать HashSet. (Если вы это сделаете, структура данных сломается, и элементы в наборе могут пропасть без вести.)

но я сомневаюсь, что вы должны использовать ArrayList, потому что если hashcode() чувствителен к изменениям объекта, затем equals(Object) скорее всего тоже. А это значит, что contains(...) и подобные методы не смогут найти предметы.

Я думаю, вы должны использовать Map введите и используйте "идентификатор студента" в качестве ключа.

(вы также можете переопределить hashcode и equals так что равенства означает, что два объекта имеют одинаковый идентификатор. Но это делает equals(Object) бесполезно для других целей.)


когда дело доходит до поведения ArrayList и HashSet это совершенно разные классы.

ArrayList

  • ArrayList не проверять дубликаты.
  • get() is O(1)
  • contains() is O(n) но вы полностью контролируете порядок записей.

                          get  add  contains next remove(0) iterator.remove
    ArrayList             O(1) O(1) O(n)     O(1) O(1)      O(1)
    
  • не потокобезопасный и сделать его потокобезопасным вы должны использовать Collections.synchronizedList(...)

поиска HashSet

  • HashSet гарантирует, что нет никаких дубликатов.
  • дает O(1) contains() метод, но не сохраняет порядок.

                          add      contains next     notes
    HashSet               O(1)     O(1)     O(h/n)   h is the table 
    
  • не потокобезопасный и сделать его потокобезопасным вы должны использовать Collections.synchronizedSet(...)

Это зависит. Как вы говорите о студенте, так должно быть, есть что-то вроде id или rollno, которое уникально. Если да, то переопределить метод hashcode и реализовать хэш-код на основе их идентификаторов. Тогда нет никакого влияния на хэш-код путем изменения любого из других свойств student.

выбрать набор или список полностью зависит от ваших требований. Прочтите эту ссылку, и она прояснит разницу между Set и list
в чем разница между Set и List?

и если вы используете объекты в наборе, вы можете попытаться переопределить оба хэш-код и метод equals Так что контроль уникальности в ваших руках.


вы не должны использовать Set когда результаты объектов' equals методы будут меняться. Если вы идентифицируете студентов по стабильному уникальному идентификационному номеру и equals просто проверяет этот идентификатор, а затем использует Set - Это хорошо.

отметим, что HashSet использовать hashCode для индексирования и сравнения, и hashCode должны включать именно те поля, которые используются для определения equals.


для хэшированной коллекции, такой как HashSet, ключ должен быть immutable. Hashset использует хэширование внутри, чтобы решить ведро для хранения объекта. А также при получении объекта он будет использовать хэш, чтобы найти ведро объект. Если вы меняете объект после хранения, он может изменить хэш-код объекта, и Set не сможет получить правильный объект. Если вам нужно изменить объект даже после добавления его в коллекцию, использование хэшированной коллекции не является хорошим выбор. Скорее идите за Arraylist, но обратите внимание, что с ArrayList вы потеряете преимущество, чтобы быстро получить желаемого студента, как это может быть с набором.


javadoc для Set говорит

Примечание: необходимо проявлять большую осторожность, если изменяемые объекты используются в качестве набора элементы. поведение набора не задается, если значение объект изменяется таким образом, что влияет на сравнения equals объект является элементом в наборе. особый случай запрет заключается в том, что набор не может содержать себя в качестве элемента.

Итак, если вы собираюсь использовать HashSet Если вы hashCode() и equals() на основе inmutable полей, тогда у вас не будет этой проблемы. Например, используя уникальный studentID для каждого экземпляра.


из вашего требования я подумал, что лучшей структурой должна быть карта. Set фактически использует структуру карты внутри, и Вам также нужно позаботиться о переопределении метода equals для лучшего поиска. И set и arraylist найти целевой объект нужно взять некоторый алгоритм поиска, поэтому он не так эффективен, как вы ожидали (особенно в очень большой ситуации с коллекцией). Даже карта будет тратить некоторое пространство, но если ваш ID является каким-то примитивным типом, вы можете рассмотреть примитивный тип реализация карты в клад библиотека.


вопрос: какую структуру данных я должен использовать для наилучшей реализации этого? Поскольку я буду изменять свойство объектов Student в set студент (тем самым изменяя хэш-коды) должен ли я использовать ArrayList вместо?

определенно, если вы собираетесь изменить значения, используемые hashCode или equals, невозможно использовать HashMap или HashSet.

вы говорите, что вы хотите удалить и добавить много. Вопрос в том, хочешь ли ты это сделать. sequntially или случайным образом(исходя из индекса). Если вы добавляете, последовательно удаляете, то определенно лучшим выбором является LinkedList. Если вы получаете доступ к объектам случайным образом, ArrayList намного эффективнее.


Если у вас есть дубликаты данных в коде, вы должны использовать ArrayList, иначе вы можете использовать hashset, как показано ниже Таким образом, если вашему коду не нужны повторяющиеся значения, используйте Set вместо list, потому что набор даст гораздо лучшую производительность (O(n) vs O(n^2) для списка), и это нормально, потому что избегание дубликатов является самой целью набора.

ArrayList

public static void main (String[] args) {

ArrayList arr =new ArrayList();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr);  //As we are using Arraylist therefore 
                          //the duplicate elements are allowed therefore
                          //"Hello" is not removed in the output

}

поиска HashSet

public static void main (String[] args) {

HashSet arr =new HashSet();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr);  //As we are using Hashset therefore 
                          //the duplicate elements removed therefore
                          //"Hello" is removed in the output

}