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

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

453 голосов
/ 04 января 2012

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

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

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

Ответы [ 11 ]

622 голосов
/ 04 января 2012

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

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

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>.

В качестве альтернативы, вы можете использовать Multisets (также известный как Bags ) , то есть 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);

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

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

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

3. Сверните список java.util.PriorityQueue

Хотя в Java нет отсортированного списка, тем не менее, есть отсортированная очередь, которая, вероятно, сработает для вас. Это java.util.PriorityQueue класс.

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

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

Предупреждение об итераторе 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, который сортирует каждый раз, когда вы добавляете новый элемент. Это может привести к довольно сложным вычислениям в зависимости от вашей реализации и будет бессмысленным , если только вы не захотите сделать это в качестве упражнения по двум основным причинам:

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

64 голосов
/ 04 января 2012

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

24 голосов
/ 04 января 2012

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

РЕДАКТИРОВАТЬ:

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

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

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

15 голосов
/ 22 декабря 2015

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

enter image description here


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

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

JavaFX SortedList

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

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

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

9 голосов
/ 10 июня 2015

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

4 голосов
/ 04 января 2012

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

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

3 голосов
/ 04 января 2012

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

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

2 голосов
/ 23 июля 2012

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

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

1 голос
/ 27 января 2014

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

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