Почему в Java нет SortedList?
В Java есть интерфейсы SortedSet
и SortedMap
. Оба принадлежат Java Collections framework и предоставляют отсортированный способ доступа к элементам.
Однако, в моем понимании, в Java нет SortedList
. Вы можете использовать java.util.Collections.sort()
для сортировки списка.
Есть идеи, почему это так разработано?
Переведено автоматически
Ответ 1
Итераторы списков в первую очередь гарантируют, что вы получите элементы списка во внутреннем порядке списка (он же. порядок вставки). Более конкретно, это зависит от порядка, в котором вы вставили элементы, или от того, как вы манипулировали списком. Сортировку можно рассматривать как манипулирование структурой данных, и есть несколько способов отсортировать список.
Я упорядочу способы в порядке полезности, как я лично это вижу:
1. Рассмотрите возможность использования коллекций Set
или Bag
ПРИМЕЧАНИЕ: Я поместил этот параметр вверху, потому что это то, что вы обычно хотите делать в любом случае.
Сортированный набор автоматически сортирует коллекцию при вставке, что означает, что он выполняет сортировку при добавлении элементов в коллекцию. Это также означает, что вам не нужно сортировать ее вручную.
Более того, если вы уверены, что вам не нужно беспокоиться о дублирующихся элементах (или иметь их), то вы можете использовать TreeSet<T>
вместо этого. Он реализует интерфейсы SortedSet
и NavigableSet
и работает так, как вы, вероятно, ожидаете от списка:
TreeSet<String> set = new TreeSet<String>();
set.add("lol");
set.add("cat");
// automatically sorts natural order when adding
for (String s : set) {
System.out.println(s);
}
// Prints out "cat" and "lol"
Если вам не нужен естественный порядок, вы можете использовать параметр конструктора, который принимает значение Comparator<T>
.
В качестве альтернативы вы можете использовать мультимножества (также известные как пакеты), то есть Set
которые допускают дублирование элементов, вместо этого существуют их сторонние реализации. Наиболее примечательно, что из библиотек Guava есть TreeMultiset
, которая работает очень похоже на TreeSet
.
2. Отсортируйте свой список с помощью Collections.sort()
Как упоминалось выше, сортировка List
s - это манипулирование структурой данных. Итак, для ситуаций, когда вам нужен "один источник истины", который будет отсортирован различными способами, лучше всего выполнить сортировку вручную.
Вы можете отсортировать свой список с помощью java.util.Collections.sort()
метода. Вот пример кода о том, как:
List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");
Collections.sort(strings);
for (String s : strings) {
System.out.println(s);
}
// Prints out "cat" and "lol"
Использование компараторов
Одним из явных преимуществ является то, что вы можете использовать Comparator
в sort
методе. Java также предоставляет некоторые реализации для Comparator
таких как Collator
, которые полезны для сортировки строк с учетом локали. Вот один пример.:
Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
Sorting in concurrent environments
Однако обратите внимание, что использование sort
метода неудобно в параллельных средах, поскольку экземпляром коллекции будут манипулировать, и вам следует рассмотреть возможность использования неизменяемых коллекций вместо этого. Это то, что Guava предоставляет в Ordering
классе и представляет собой простой однострочный:
List<string> sorted = Ordering.natural().sortedCopy(strings);
3. Завершите свой список с помощью java.util.PriorityQueue
Хотя в Java нет отсортированного списка, однако есть отсортированная очередь, которая, вероятно, будет работать так же хорошо для вас. Это класс java.util.PriorityQueue
.
Нико Хаазе в комментариях сослался на связанный вопрос, который также отвечает на этот вопрос.
В отсортированной коллекции вы, скорее всего, не хотите манипулировать внутренней структурой данных, поэтому PriorityQueue не реализует интерфейс списка (потому что это дало бы вам прямой доступ к его элементам).
Предостережение относительно PriorityQueue
итератора
PriorityQueue
Класс реализует интерфейсы Iterable<E>
и Collection<E>
, поэтому его можно повторять как обычно. Однако не гарантируется, что итератор вернет элементы в отсортированном порядке. Вместо этого (как указывает Алдерат в комментариях) вам нужно poll()
сохранять очередь пустой.
Обратите внимание, что вы можете преобразовать список в очередь с приоритетом с помощью конструктора, который принимает любую коллекцию:
List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");
PriorityQueue<String> sortedStrings = new PriorityQueue(strings);
while(!sortedStrings.isEmpty()) {
System.out.println(sortedStrings.poll());
}
// Prints out "cat" and "lol"
4. Напишите свой собственный SortedList
класс
ПРИМЕЧАНИЕ: Вам не обязательно это делать.
Вы можете написать свой собственный класс List, который выполняет сортировку каждый раз, когда вы добавляете новый элемент. Это может занять довольно много времени в зависимости от вашей реализации и бессмысленно, если только вы не хотите выполнять это в качестве упражнения по двум основным причинам:
- Это нарушает контракт, заключенный с
List<E>
интерфейсом, потому чтоadd
методы должны гарантировать, что элемент будет находиться в индексе, указанном пользователем. - Зачем изобретать велосипед? Вместо этого вы должны использовать TreeSet или Multisets, как указано в первом пункте выше.
Однако, если вы хотите сделать это в качестве упражнения, вот пример кода для начала, в нем используется AbstractList
абстрактный класс:
public class SortedList<E> extends AbstractList<E> {
private ArrayList<E> internalList = new ArrayList<E>();
// Note that add(E e) in AbstractList is calling this one
@Override
public void add(int position, E e) {
internalList.add(e);
Collections.sort(internalList, null);
}
@Override
public E get(int i) {
return internalList.get(i);
}
@Override
public int size() {
return internalList.size();
}
}
Обратите внимание, что если вы не переопределили нужные вам методы, то реализации по умолчанию из AbstractList
выдадут UnsupportedOperationException
s.
Ответ 2
Потому что концепция списка несовместима с концепцией автоматически отсортированной коллекции. Смысл списка в том, что после вызова list.add(7, elem)
вызов list.get(7)
вернется elem
. При автоматической сортировке списка элемент может оказаться в произвольной позиции.
Ответ 3
Поскольку все списки уже "отсортированы" по порядку добавления элементов (порядок FIFO), вы можете "прибегнуть" к ним с другим порядком, включая естественный порядок элементов, используя java.util.Collections.sort()
.
Редактировать:
Списки как структуры данных основаны на том, что интересно, так это порядок, в котором вставляются элементы.
Наборы не содержат этой информации.
Если вы хотите упорядочить, добавив время, используйте List
. Если вы хотите упорядочить по другим критериям, используйте SortedSet
.
Ответ 4
Set и Map представляют собой нелинейную структуру данных. List - это линейная структура данных.
Древовидная структура данных SortedSet
и SortedMap
интерфейсы реализуют TreeSet
и TreeMap
соответственно, используя используемый алгоритм реализации красно-черного дерева. Таким образом, это гарантирует отсутствие дублирующихся элементов (или ключей в случае Map
).
List
уже поддерживается упорядоченная коллекция и структура данных на основе индекса, деревья не являются структурами данных на основе индекса.Tree
по определению не может содержать дубликатов.- В
List
у нас могут быть дубликаты, поэтому их нетTreeList
(т.е. нетSortedList
). - Список поддерживает элементы в порядке вставки. Поэтому, если мы хотим отсортировать список, мы должны использовать
java.util.Collections.sort()
. Указанный список сортируется в порядке возрастания в соответствии с естественным порядком расположения его элементов.