Какая лучшая реализация списка для больших списков в java

Мне нужно создать большой список из n элементов (может быть до 100 000). каждый элемент в списке является целым числом, эквивалентным индексу списка. После этого я должен вызвать Collections.shuffle в этом списке. Мой вопрос заключается в том, какая реализация списка (либо коллекции java, либо коллекции apache). Мое чувство кишки - ArrayList, которое можно использовать здесь. Все мысли приветствуются. Спасибо!

Спасибо за входные данные. Я думаю, что я придерживаюсь ArrayList. В настоящее время я использую конструктор ArrayList с параметром initialCapacity и передаю размер списка. Поэтому, если исходный список равен 100000, я создаю этот новый список с новым ArrayList (100000); Поэтому я думаю, что у меня нет создания массива и сделать asList, так как не будет никакого изменения размера. Кроме того, большинство списков коллекций apache, таких как GrowthList и LazyList, не реализуют RandomAccess. Это наверняка замедлило бы тасование (согласно javadocs). FastArrayList реализует RandomAccess, но apache имеет примечание для этого класса, говорящее: "Этот класс не является межплатформенным. Использование его может вызвать непредвиденные сбои на некоторых архитектурах".

Ответ 1

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

Ответ 2

Цитируется из коллекции Collections.shuffle javadoc:

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

Итак, если у вас нет других потребностей, я бы пошел с ArrayList, который реализует RandomAccess.

Ответ 3

Создание массива Integer, а затем его перенос с Arrays.asList дает вам еще меньше накладных расходов, чем обычный ArrayList.

List<Integer> makeList(int size){
    if (size < 0) throw new IllegalArgumentException();
    Integer[] arr = new Integer[size];
    for (int i = 0; i < arr.length; ++i) arr[i] = i;
    List<Integer> list = Arrays.asList(arr);
    Collection.shuffle(list);
    return list;
}

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

Ответ 4

ArrayList<T>, вероятно, будет хорошо, да, но какие критерии вы используете для "наилучшего"? И насколько хорошо это должно быть в любом случае? Каковы ваши компромиссы между сложностью и "добротой" во всех этих критериях?

Ответ 5

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

Ответ 6

Google Guava библиотека имеет некоторую действительно приятную примитивную обработку, включая Ints.asList() возвращает список, который можно перетасовать.

Проект Guava все еще находится на предварительном этапе развертывания, хотя код тщательно анализируется и широко используется в Google. Вам нужно будет получить код из SVN и создать класс com.google.common.primitive.

Ответ 7

Недавно была реализована реализация List под названием GlueList, которая очень быстро, чем ArrayList и LinkedList.

Ответ 8

Это касается вашего обновления вашего вопроса относительно FastArrayList.

FastArrayList реализует RandomAccess но apache имеет примечание для этого класса, в котором говорится: "Этот класс не является кроссплатформенным. RandomAccess использование может вызвать непредвиденные сбои в некоторых архитектурах".

Класс FastArrayList (javadoc) является классом одновременного списка. Вот что говорит Javadoc:

Индивидуальная реализация java.util.ArrayList, предназначенная для работы в многопоточной среде, где подавляющее большинство вызовов методов доступно только для чтения, а не для структурных изменений. При работе в "быстром" режиме вызовы чтения не синхронизированы, а вызовы записи выполняют следующие шаги:

  1. Клонировать существующую коллекцию
  2. Выполните модификацию на клоне
  3. Заменить существующую коллекцию (измененным) клоном

[...]

ПРИМЕЧАНИЕ. Если вы создаете ArrayList и получаете к нему доступ только в пределах одного потока, вы должны использовать java.util.ArrayList напрямую (без синхронизации) для максимальной производительности.

ПРИМЕЧАНИЕ. Этот класс не является кроссплатформенным [из-за проблем с быстрым режимом и несколькими потоками]

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

  • Проблема "кроссплатформенности" не актуальна, поскольку она затрагивает только многопоточные сценарии использования.
  • Первое "ПРИМЕЧАНИЕ" говорит (ясно), что для однопоточного приложения лучше использовать ArrayList.

Короче говоря, "fast" в FastArrayList относится (скажем) к выполнению этого:

  List<String> myConcurrentlList = Collections.synchronizedList(new ArrayList<>());

Вернуться к исходному вопросу. ArrayList - самый простой из быстрых способов, и я сомневаюсь, что любой другой класс List превзойдет его. Однако следующий подход может быть быстрее.

  String[] array = new String[...];
  // populate array
  // shuffle array ... using same algorithm as Collections.shuffle
  for (int i = array.length; i > 1; i--)
      swap(array, i - 1, rnd.nextInt(i));
  }
  List<String> list = Arrays.asList(array);

Почему это может быть быстрее? Потому что операции подкачки в массиве будут быстрее, чем в ArrayList.

Будет ли это быстрее в целом? Тяжело сказать. Это зависит от:

  • создаете ли вы/заполняете массив таким образом, не является ли это дополнительной работой?
  • сравнивается ли производительность операций со списком в asList с ArrayList... и какие операции вы выполняете и т.д.

Мой совет - остерегаться "преждевременной оптимизации".

Ответ 9

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

Но если вы действительно оцениваете производительность, вы можете рассмотреть возможность использования int [] или пользовательского списка, основанного на int [], как и во всех стандартных реализациях List и List, которые вы будете боксировать и распаковывать ints в Integer.

Это не будет проблемой для суффе, поскольку это будет просто переупорядочение указателей, но вы будете создавать 100 000 объектов, когда вам это может не понадобиться. Предполагая, что вы знаете размер своего списка перед созданием, вы можете легко создать новый класс List, который обертывает примитивный массив. Если вы используете java.util.List, вам все равно нужно будет поместить возврат из любого метода get.

Ответ 10

Вы также можете использовать реализацию списков на основе сопоставленных файлов. В такой реализации список не полностью присутствует в памяти, но в памяти будет активна только часть огромного списка. Если вы достигли ограничения пространства кучи (в основном, в 32-битном jvm), вам может понадобиться сделать список, который легко удаляет данные, используя файл с отображением памяти, который будет быстрее обычного ввода-вывода файлов. Одна такая реализация описана в этом коде Google и объясняется в этой ссылке.