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

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

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

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


person Cruel    schedule 28.05.2011    source источник
comment
Посмотрите на ответ на этот вопрос, который я задал несколько дней назад: stackoverflow.com/questions/6129805/   -  person Renato Dinhani    schedule 28.05.2011
comment
В папке, в которой установлен jdk, находится файл src.zip. Это архив с исходным кодом java-классов. Я настоятельно рекомендую изучить структуру и внутреннее устройство этих классов, чтобы лучше понять, как работают классы Java.   -  person    schedule 17.09.2015
comment
Еще один момент. По умолчанию размер ArrayDeque равен 16. Когда он заполнен, ArrayDeque удваивает свой размер. Элементы копируются в новый массив после удвоения размера. Лучше инициализировать ArrayDeque с начальным размером.   -  person Vineeth Chitteti    schedule 27.08.2020
comment
Еще один момент, о котором стоит упомянуть, заключается в том, что в LinkedList вы можете использовать индексы для итерации по его элементам, в то время как ArrayDeque не поддерживает доступ на основе индекса.   -  person Java Main    schedule 17.04.2021


Ответы (8)


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

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

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

person bestsss    schedule 28.05.2011
comment
Еще одно отличие, о котором следует помнить: LinkedList поддерживает нулевые элементы, а ArrayDeque - нет. - person Luke Usherwood; 10.07.2013
comment
Еще один небольшой недостаток (для приложений реального времени) заключается в том, что при выполнении операции push / add требуется немного больше, когда внутренний массив ArrayDeque заполнен, так как он должен удвоить свой размер и скопировать все данные. - person Andrei I; 13.09.2013
comment
@AndreiI, это только одна сторона дела. Даже если вы исключите затраты на итерацию для приложения в реальном времени и возможность предварительно выделить необходимую емкость, GC может потребоваться выполнить итерацию всего LinkedList. По сути, вы переносите затраты (которые при загрузке выше) в сборщик мусора. - person bestsss; 19.05.2014
comment
@bestsss, почему добавление / удаление по голове будет хуже для LinkedList? - person David T.; 16.10.2014
comment
@DavidT. b / c это связано с затратами на сборщик мусора для освобожденного узла, назначение заголовка также может потребовать маркировки карты (опять же, для сборщика мусора, если LinkedList уже находится в постоянном поколении) ... и это в дополнение к дополнительному косвенному обращению (кеш- miss), чтобы вернуть элемент и повторно установить связь. - person bestsss; 17.10.2014
comment
Кроме того, LinkedList реализует List, а ArrayDeque - нет. Это означает, что у LinkedList есть такие методы, как indexOf или remove(int), а у ArrayDeque их нет. Иногда это может быть важно. - person ZhekaKozlov; 02.09.2015
comment
добрый опоздал на эту вечеринку. Для The only better operation of a linked list is removing the current element during iteration. вы имеете в виду такой метод, как remove(), который удаляет заголовок очереди? потому что связанный список также работает без сбоев. - person Huazhe Yin; 06.08.2019
comment
@HuazheYin звонит remove() на Iterator или ListIterator - person Holger; 08.04.2020
comment
Связанные структуры, возможно, являются худшей структурой для итерации с пропуском кеша для каждого элемента. -------что это значит? Что такое промах кеша? - person ZhaoGang; 21.05.2020
comment
@ZhaoGang ArrayDeque напоминает массивы и распределяет память в смежных блоках памяти, в отличие от LinkedList, где память выделяется в несмежном пространстве памяти. Поскольку данные хранятся в непрерывном пространстве, данные будут храниться в кеше довольно легко. Это будет трудоемкой задачей для LinkedList и, следовательно, вероятностью промаха кеша. - person Rahul Raj; 17.06.2021

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

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

person coderodde    schedule 17.09.2015
comment
Можете ли вы сказать мне, как добавление / удаление элемента из головы лучше в связанном, чем в массиве? Разве LinkedList не должен иметь преимущества, поскольку изменяются только ссылки на prev и next, в то время как в ArrayDeque необходимо смещать многие элементы? - person Stefan; 15.11.2020

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

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

person Chris Jester-Young    schedule 28.05.2011

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

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

В тестовой установке учитываются:

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

Результат испытаний:

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

График:

введите описание изображения здесь

Вывод:

  • Если ваше требование хранит 100 или 200 элементов, использование любой из очередей не будет иметь большого значения.
  • Однако, если вы разрабатываете на мобильных устройствах, вы можете использовать ArrayList или ArrayDeque с хорошим предположением о максимальной емкости, которая может потребоваться в списке из-за строгих ограничений памяти.
  • Существует много кода, написанного с использованием LinkedList, поэтому будьте осторожны при принятии решения об использовании ArrayDeque, особенно потому, что он НЕ реализует List интерфейс (я думаю, что это достаточно большая причина). Возможно, ваша кодовая база активно взаимодействует с интерфейсом List, и, скорее всего, вы решите использовать ArrayDeque. Использование его для внутренних реализаций может быть хорошей идеей ...
person Manish Kumar Sharma    schedule 20.06.2017
comment
Как этот тест будет фиксировать время сборки мусора, вызванное мусором связанного списка? - person 0xbe5077ed; 06.07.2017

ArrayDeque и LinkedList реализуют Deque, но реализация отличается.

Ключевые отличия:

  1. Класс ArrayDeque - это реализация массива с изменяемым размером интерфейса Deque, а класс LinkedList - реализация списка

  2. Элементы NULL можно добавить в LinkedList, но не в ArrayDeque

  3. ArrayDeque более эффективен, чем LinkedList для операций добавления и удаления на обоих концах, а реализация LinkedList эффективна для удаления текущего элемента во время итерации.

  4. Реализация LinkedList потребляет больше памяти, чем ArrayDeque

Поэтому, если вам не нужно поддерживать элементы NULL &&, ища меньше памяти && эффективности добавления / удаления элементов с обоих концов, ArrayDeque - лучший вариант.

Дополнительные сведения см. В документации.

person Ravindra babu    schedule 18.09.2015
comment
В связанном списке для поиска последнего элемента потребуется O (N). не совсем так. LinkedList реализован как двусвязный список, поэтому вам не нужно перемещаться по списку, чтобы получить последний элемент (header.previous.element). Заявление об эффективности памяти также может быть оспорено, поскольку размер резервного массива всегда изменяется до следующей степени 2. - person Clément MATHIEU; 21.09.2015
comment
Потребуется O (N), чтобы найти НЕПРАВИЛЬНЫЙ последний элемент. Связанный список содержит ссылку на последний узел, и LinkedList.descendingIterator () получает этот узел. Таким образом, мы получаем производительность O (1). См .: coffeeorientprogramming.wordpress.com/2018/04/23 / (таким образом, голосование против). - person Leo Ufimtsev; 23.04.2018
comment
Когда вы используете Iterator для доступа к последнему элементу, операция O (N) для обоих классов. Когда вы используете общий интерфейс Deque, доступ к последнему элементу составляет O (1) для обоих классов. Независимо от того, какую точку зрения вы придерживаетесь, относить O (1) к ArrayDeque и O (N) к LinkedList одновременно, неправильно. - person Holger; 08.04.2020
comment
Все ваши предложения приняты и исправлено содержание - person Ravindra babu; 25.04.2020

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

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

person rekinyz    schedule 07.02.2015

Это не всегда так.

Например, в приведенном ниже случае linkedlist имеет лучшую производительность, чем ArrayDeque в соответствии с leetcode 103.

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> rs=new ArrayList<>();
        if(root==null)
            return rs;
        // ???? here ,linkedlist works better
        Queue<TreeNode> queue=new LinkedList<>();
        queue.add(root);
        boolean left2right=true;
        while(!queue.isEmpty())
        {
            int size=queue.size();
            LinkedList<Integer> t=new LinkedList<>();
            while(size-->0)
            {
                TreeNode tree=queue.remove();
                if(left2right)  
                    t.add(tree.val);
                else
                    t.addFirst(tree.val);
                if(tree.left!=null)
                {
                    queue.add(tree.left);
                }
                if(tree.right!=null)
                {
                    queue.add(tree.right);
                }
            }
            rs.add(t);
            left2right=!left2right;
        }
        return rs;
    }
}
person Red    schedule 26.03.2020

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

person Piyush Yawalkar    schedule 21.09.2015
comment
Если вы имеете в виду LinkedList в Java Collection, он имеет двойную связь и имеет быстрый доступ к голове и хвосту, поэтому доступ к последнему элементу также занимает O (1). - person Maurice; 15.07.2016
comment
Доступ к последнему элементу в LinkedList не O (N). Если вы используете спускающийсяIterator (), он выполняется за O (1). См. coffeeorientprogramming.wordpress.com/2018/04/23/ (таким образом, голос против). - person Leo Ufimtsev; 23.04.2018
comment
Оба класса не являются потокобезопасными. И нет связи между началом предложения «необходима синхронизация вручную» и его концом «они быстрее». - person Holger; 08.04.2020