Почему в Java нет SortedList?

в Java есть SortedSet и SortedMap интерфейсы. Оба принадлежат к стандартной структуре коллекций Java и предоставляют сортированный способ доступа к элементам.

однако, в моем понимании нет SortedList в Java. Вы можете использовать java.util.Collections.sort() для сортировки списка.

есть идеи, почему он так спроектирован?

10 ответов


итераторы списка гарантируют в первую очередь, что вы получите элементы списка во внутреннем порядке списка (он же. порядок вставки). Более конкретно, это в порядке, в котором вы вставили элементы или о том, как вы манипулировали списком. Сортировка может рассматриваться как манипуляция структурой данных, и существует несколько способов сортировки списка.

я закажу пути в порядке полезность как я лично вижу это:

1. Рассмотрите возможность использования Set или коллекции

Примечание: я поставил эту опцию наверху, потому что это то, что вы обычно хотите сделать в любом случае.

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

кроме того, если вы уверены, что вы не нужно беспокоиться о (или иметь) повторяющиеся элементы, то вы можете использовать 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>.

кроме того, вы можете использовать Multisets (также известный как сумки), что является Set что позволяет дублировать элементы, вместо этого и есть сторонние реализации из них. Особенно от гуава библиотеки есть TreeMultiset, это работает очень похоже на TreeSet.

2. Сортировка списка с помощью Collections.sort()

как упоминалось выше, сортировка Lists-это манипуляция структурой данных. Поэтому для ситуаций, когда вам нужен "один источник истины" , который будет отсортирован различными способами, затем сортировка это вручную-это путь.

вы можете отсортировать свой список с помощью 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);

сортировка в параллельных средах

обратите внимание, что с помощью sort метод не является дружественным в параллельных средах, так как экземпляр коллекции будет управляться, и вы должны рассмотреть возможность использования неизменяемых коллекций вместо этого. Это то, что гуава предоставляет в Ordering класс и простой однострочный:

List<string> sorted = Ordering.natural().sortedCopy(strings);

3. Оберните свой список с java.util.PriorityQueue

Хотя нет сортированный список в Java есть, однако, сортированная очередь, которая, вероятно, будет работать так же хорошо для вас. Это java.util.PriorityQueue класса.

Нико Хаасе связан в комментариях к вопрос это также отвечает на это.

в отсортированной коллекции вы скорее всего не хотите манипулировать внутренняя структура данных, поэтому PriorityQueue не реализует интерфейс списка (потому что это даст вам прямой доступ к его элементам).

нюанс на PriorityQueue итератор

на PriorityQueue класс реализует Iterable<E> и Collection<E> интерфейсы, поэтому он может использоваться как обычно. Однако итератор не гарантирует возврат элементов в отсортированном порядке. Вместо этого (как указывает Alderath в комментариях) вам нужно 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 класс

Примечание: вы не должны этого делать.

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

  1. это нарушает контракт, который List<E> интерфейс имеет, поскольку add методы должны гарантировать, что элемент будет находиться в индексе, которые указывает пользователь.
  2. зачем изобретать велосипед? Вы должны вместо этого использовать TreeSet или Мультимножества как указано в первом пункте.
, если вы хотите сделать это в качестве упражнения вот пример кода, чтобы вы начали, он использует 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 бросит UnsupportedOperationExceptions.


потому что концепция списка несовместима с концепцией автоматически отсортированной коллекции. Смысл списка в том, что после вызова list.add(7, elem) вызов list.get(7) вернутся elem. С автоматически отсортированным списком элемент может оказаться в произвольной позиции.


поскольку все списки уже " отсортированы "по порядку, элементы были добавлены (заказ FIFO), вы можете" прибегнуть " к ним с другим порядком, включая естественный порядок элементов, используя java.util.Collections.sort().

EDIT:

списки как структуры данных основаны на том, что интересно, это порядок, в котором элементы, где вставлены.

наборы не имеют этой информации.

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


Set и Map являются нелинейной структурой данных. Список-это линейная структура данных.

enter image description here


структура данных дерева SortedSet и SortedMap интерфейсы реализует TreeSet и TreeMap соответственно, используя used красно-черное дерево реализация. Таким образом, он гарантирует, что нет дублированных элементов (или ключей в случае Map).

  • List уже поддерживает упорядоченную коллекцию и индексная структура данных, деревья не являются индексными структурами данных.
  • Tree по определению не может содержать дубликаты.
  • на List у нас могут быть дубликаты, поэтому нет TreeList(т. е. SortedList).
  • список хранит элементы в порядке вставки. Поэтому, если мы хотим отсортировать список, мы должны использовать java.util.Collections.sort(). Сортирует указанный список по возрастанию в соответствии с естественным порядком его элементов.

для любых новичков, по состоянию на апрель 2015 года, Android теперь имеет SortedList - класс в библиотеке, специально разработанное для работы с RecyclerView. Вот блоге об этом.


JavaFX SortedList

хотя это заняло некоторое время, Java 8 имеет сортированный List. http://docs.oracle.com/javase/8/javafx/api/javafx/collections/transformation/SortedList.html

как вы можете видеть в javadocs, это часть JavaFX коллекции, предназначенные для предоставления отсортированного представления в ObservableList.

Update: обратите внимание, что с Java 11 инструментарий JavaFX переместился за пределы JDK и теперь является отдельной библиотекой. JavaFX 11 доступен как загружаемый SDK или из MavenCentral. См.https://openjfx.io


другой момент-временная сложность операций вставки. Для вставки списка ожидается сложность O (1). Но это не может быть гарантировано отсортированным списком.

и самый важный момент заключается в том, что списки ничего не предполагают о своих элементах. Например, можно составить списки вещей, которые не реализуют equals или compare.


подумайте об этом так:List интерфейс имеет такие методы, как add(int index, E element), set(int index, E element). Контракт заключается в том, что после добавления элемента в позицию X вы найдете его там, если не добавите или не удалите элементы перед ним.

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


первая строка в списке API говорит, что это упорядоченная коллекция (также известная как последовательность). Если вы сортируете список, вы не можете поддерживать порядок, поэтому в Java нет списка деревьев.
Как говорит API, список Java вдохновлен последовательностью и см. свойства последовательностиhttp://en.wikipedia.org/wiki/Sequence_ (математика)

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


рассмотрите возможность использования indexed-tree-map . Это расширенный набор деревьев JDK, который предоставляет доступ к элементу по индексу и находит индекс элемента без итерации или скрытых базовых списков, которые создают резервную копию дерева. Алгоритм основан на обновлении Весов изменяющихся узлов при каждом изменении.