Почему ArrayDeque лучше, чем LinkedList

Я пытаюсь понять почему ArrayDeque Java лучше, чем LinkedList Java поскольку они оба реализуют интерфейс Deque.

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

Если я понимаю, я буду более уверенно использовать его. Я не мог четко понять реализацию JDK относительно того, как она управляет ссылками head и tail.

7 ответов


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

Если вам нужно добавить/удалить в оба конца, ArrayDeque значительно лучше, чем связанный список. Произвольный доступ каждый элемент также O (1) для циклической очереди.

только лучше операция это удаление текущего элемента во время итерации.


Я считаю, что основным "узким местом" в LinkedList Это тот факт, что всякий раз, когда вы нажимаете на любой конец deque, за сценой реализация выделяет новый узел связанного списка, который по существу включает JVM/OS, и это дорого. Кроме того, всякий раз, когда вы поп с любого конца, внутренние узлы LinkedList получить право на сбор мусора,и это больше работы за кулисами. Кроме того, поскольку узлы связанного списка выделены здесь и там, использование кэша процессора не будет предоставить много пользы.

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


ArrayDeque является новым С Java 6, поэтому многие коды (особенно проекты, которые пытаются быть совместимыми с более ранними версиями Java) не используют его.

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


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

но это не значит, что я бы слепо принимать LinkedListили ArrayDeque'ы стороны. Если вы хотите знать, посмотрите на ниже benchmark сделал Брайан.

настройка теста считает:

  • каждый тестовый объект представляет собой строку из 500 символов. Каждая строка-это отдельный объект в памяти.
  • размер массива теста будет поменян во время тестов.
  • для каждой комбинации размера массива / очереди-реализации выполняется 100 тестов и вычисляется среднее время на тест.
  • каждый тест состоит из заполнения каждой очереди всеми объектами, а затем их удаления.
  • мера время в миллисекундах.

Результат Теста:

  • ниже 10 000 элементов, тесты LinkedList и ArrayDeque усреднены на уровне ниже 1 мс.
  • по мере увеличения наборов данных различия между средним временем тестирования ArrayDeque и LinkedList увеличиваются.
  • при тестовом размере 9,900,000 элементов подход LinkedList занял ~165% больше времени, чем ArrayDeque подход.

график:

enter image description here

вывод:

  • если ваше требование хранит 100 или 200 элементов, то оно не сделало бы большая разница в использовании любой из очередей.
  • однако, если вы разрабатываете на мобильном телефоне, вы можете использовать ArrayList или ArrayDeque С хорошей догадкой максимальной емкости что список может потребоваться из-за строгой ограничение памяти.
  • существует много кода, написанного с помощью LinkedList поэтому будьте осторожны при решении использовать ArrayDeque тем более, что он не реализует List интерфейс(я думаю, что это достаточно большая причина). Возможно, ваша кодовая база активно разговаривает с интерфейсом списка, скорее всего, и вы решите перейти к ArrayDeque. Используя его для внутренних реализаций может быть хорошей идеей...

доступ к элементу в ArrayDeque всегда быстрее по сравнению с LinkedList с O (1) для доступа к элементам. В связанном списке для поиска последнего элемента потребуется O(N).

ArrayDeque эффективен для памяти, так как вам не нужно отслеживать следующий узел, в отличие от связанного списка.

даже согласно документации java, было указано, что

ArrayDeque-реализация изменяемого размера массива интерфейса Deque. Двусторонней очередью массива имеют возможности ограничения; они растут по мере необходимости для поддержки использования. Они не являются потокобезопасными; в отсутствие внешней синхронизации они не поддерживают одновременный доступ несколькими потоками. Нулевые элементы запрещены. Этот класс, вероятно, будет быстрее стека при использовании в качестве стека и быстрее LinkedList при использовании в качестве очереди.

бенчмаркинг из этих двух доказывает, что ArrayDeque быстрее.


хотя ArrayDeque<E> и LinkedList<E> есть и реализован Deque<E> интерфейс, но ArrayDeque использует в основном массив объектов E[] для хранения элементов внутри своего объекта, поэтому он обычно использует индекс для размещения элементов головы и хвоста.

одним словом, он просто работает как Deque (со всем методом Deque), однако использует структуру данных массива. Что касается, какой из них лучше, зависит от того, как и где вы использовать их.


сложность времени для ArrayDeque для доступа к элементу составляет O(1), а для LinkList-O (N) для доступа к последнему элементу. ArrayDeque не является потокобезопасным, поэтому необходима ручная синхронизация, чтобы вы могли получить доступ к нему через несколько потоков, и поэтому они быстрее.