2013-09-06 2 views
5

В следующем коде создается вывод [1,2], хотя hashset не сортируется.Как этот HashSet производит сортированный вывод?

Set set = new HashSet(); 
set.add(new Integer(2)); 
set.add(new Integer(1)); 
System.out.println(set); 

Почему это?

+0

Используйте несколько тестовых примеров. Включите 20 номеров и посмотрите, одинаковый ли результат. – JNL

ответ

8

Такое поведение вызвано несколькими отдельными причинами:

  • Целые хэш себя
  • в Java, HashMap с и HashSet ы сохраненные с помощью массива
  • они также изменять хэши с использованием выше бит для изменения младших бит; если хеш находится в диапазоне 0 ..15, она поэтому не модифицируется
  • , что ведро объект выходит, зависит от младших бит модифицированного хэша
  • при переборе над картой или набором, внутренняя таблица сканируются последовательно

Так что, если вам добавить несколько маленьких (< 16) целых чисел в HashMap/HashSet, это то, что происходит:

  • целое i имеет Hashcode i
  • , так как это меньше т han 16, это измененный хеш также i
  • он приземляется в ковше нет. i
  • при переборе, ковши посещаются последовательно, так что, если все, что вы там хранятся небольшие целые числа, они будут извлечены в порядке возрастания

Обратите внимание, что если начальное число ковшей слишком мал, целые может посадить в ведре не пронумерован после них:

HashSet<Integer> set = new HashSet<>(4); 
set.add(5); set.add(3); set.add(1); 
for(int i : set) { 
    System.out.print(i); 
} 

отпечатков 153.

1

HashSet - неупорядоченная коллекция. У него нет никаких гарантий и нет понятий «порядок». См. Этот ответ для получения более подробной информации: What is the difference between Set and List?

Вы можете использовать TreeSet, если вам нужно заказать, отсортированный набор.

Существует также LinkedHashSet для заказанного набора, который не отсортирован.

+0

@superEb Я на самом деле просто добавил этот комментарий к моему ответу. Похоже, мы поняли это одновременно! – Kon

0

A set в java не предполагается заказывать. Вместо этого используйте ArrayList. Также проверьте API Java Collection для дальнейшей справки.

+0

Но не используйте «Список», если элементы должны быть уникальными. – superEb

+0

'LinkedHashSet' обычно является лучшим выбором, если вы хотите быстрый поиск по постоянному времени, но с предсказуемым порядком итерации. Используйте «ArrayList», если вы пытаетесь сэкономить место и можете терпеть медленные (линейные) поисковые запросы. –

+0

@Ashwin Обратите внимание, что вы можете получить время логарифмического времени O (log n) для отсортированного списка с помощью метода 'Collections.binarySearch()'. – Kon

5

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

Однако, если вы задаетесь вопросом, почему в Java (как сейчас) конкретной реализации HashSet производит результат, который вы видите: это потому, что Integer стоимости 1 хэшей в месте во внутренней таблице входа в HashMap, что приходит до местоположение, на которое 2 хешей (обратите внимание, что HashSet действительно поддерживается HashMap с произвольными значениями). Это имеет смысл, поскольку хеш-код объекта Integer является его значением.

В самом деле, вы можете видеть это, даже если добавить еще больше числа (в пределах определенного диапазона: размер таблицы ввода, который является 16 по умолчанию):

Set<Integer> set = new HashSet<>(); 
set.add(2); 
set.add(1); 
set.add(4); 
set.add(3); 
set.add(0); 
System.out.println(set); 
 
[0, 1, 2, 3, 4] 

Итерация больше HashSet происходит путем повторения таблицы внутреннего входа, что означает, что элементы, ранее представленные в таблице, первыми.

Смежные вопросы