Я всегда был один, чтобы просто использовать:
List<String> names = new ArrayList<>();
Я использую интерфейс в качестве имени типа для переносимости , поэтому, когда я задаю такие вопросы, я могу переделать свой код.
Когда следует LinkedList
использовать снова ArrayList
и наоборот?
java
arraylist
collections
linked-list
sdellysse
источник
источник
Ответы:
Резюме
ArrayList
сArrayDeque
предпочтительнее во многих случаях использования, чемLinkedList
. Если вы не уверены - просто начните сArrayList
.LinkedList
иArrayList
две разные реализации интерфейса List.LinkedList
реализует его с помощью двусвязного списка.ArrayList
реализует его с помощью динамически изменяемого размера массива.Как и в случае стандартных операций со связанными списками и массивами, различные методы будут иметь разные алгоритмические среды выполнения.
За
LinkedList<E>
get(int index)
равно O (n) ( в среднем с n / 4 шагами), но O (1), когдаindex = 0
илиindex = list.size() - 1
(в этом случае вы также можете использоватьgetFirst()
иgetLast()
). Одно из главных преимуществLinkedList<E>
add(int index, E element)
равно O (n) ( в среднем с n / 4 шагами), но O (1), когдаindex = 0
илиindex = list.size() - 1
(в этом случае вы также можете использоватьaddFirst()
иaddLast()
/add()
). Одно из главных преимуществLinkedList<E>
remove(int index)
равно O (n) ( в среднем с n / 4 шагами), но O (1), когдаindex = 0
илиindex = list.size() - 1
(в этом случае вы также можете использоватьremoveFirst()
иremoveLast()
). Одно из главных преимуществLinkedList<E>
Iterator.remove()
является O (1) . Одно из главных преимуществLinkedList<E>
ListIterator.add(E element)
является O (1) . Одно из главных преимуществLinkedList<E>
Примечание. Многие операции требуют в среднем n / 4 шагов, в лучшем случае постоянное количество шагов (например, index = 0) и n / 2 шагов в худшем случае (середина списка)
За
ArrayList<E>
get(int index)
является O (1) . Главное преимуществоArrayList<E>
add(E element)
является O (1) амортизируется, но О (п) в худшем случае , так как массив должен быть изменен и скопированadd(int index, E element)
равно O (n) ( в среднем n / 2 шагов)remove(int index)
равно O (n) ( в среднем n / 2 шагов)Iterator.remove()
равно O (n) ( в среднем n / 2 шагов)ListIterator.add(E element)
равно O (n) ( в среднем n / 2 шагов)Примечание. Многие операции требуют в среднем n / 2 шагов, постоянное количество шагов в лучшем случае (конец списка), n шагов в худшем случае (начало списка)
LinkedList<E>
допускает вставки или удаления в постоянное время с использованием итераторов , но только последовательный доступ к элементам. Другими словами, вы можете перемещаться по списку вперед или назад, но нахождение позиции в списке занимает время, пропорциональное размеру списка. Javadoc говорит «операции, индекс в списке будет проходить по списку с начала или конца, в зависимости от того что ближе» , так что эти методы являются O (п) ( п / 4 стадии) в среднем, хотя O (1) дляindex = 0
.ArrayList<E>
с другой стороны, разрешить быстрый произвольный доступ для чтения, так что вы можете получить любой элемент за постоянное время. Но добавление или удаление из любого места, кроме конца, требует сдвига всех последних элементов, чтобы сделать отверстие или заполнить пробел. Кроме того , если добавить больше элементов , чем емкость основного массива, новый массив ( в 1,5 раза больше) выделяется, и старый массив копируется в новую, так что добавление кArrayList
является О (п) в худшем случай, но постоянный в среднем.Таким образом, в зависимости от операций, которые вы намереваетесь выполнить, вы должны выбрать соответствующие реализации. Перебор любого из списков практически одинаково дешев. (Итерирование по
ArrayList
технически быстрее, но если вы не делаете что-то действительно чувствительное к производительности, вам не стоит об этом беспокоиться - они оба константы.)Основные преимущества использования
LinkedList
возникают при повторном использовании существующих итераторов для вставки и удаления элементов. Эти операции затем можно выполнить в O (1) , изменив список только локально. В списке массивов остаток массива необходимо переместить (т.е. скопировать). С другой стороны, поиск вLinkedList
средствах, следующих за ссылками в O (n) ( n / 2 шага) для наихудшего случая, тогда как вArrayList
желаемой позиции можно вычислить математически и получить доступ в O (1) .Еще одно преимущество использования
LinkedList
возникает, когда вы добавляете или удаляете из заголовка списка, так как эти операции O (1) , в то время как они O (n) дляArrayList
. Обратите внимание, чтоArrayDeque
может быть хорошей альтернативойLinkedList
для добавления и удаления из головы, но это не такList
.Кроме того, если у вас большие списки, имейте в виду, что использование памяти также отличается. Каждый элемент
LinkedList
имеет больше издержек, так как указатели на следующий и предыдущий элементы также сохраняются.ArrayLists
не надо накладных расходов ОднакоArrayLists
занимайте столько памяти, сколько выделено для емкости, независимо от того, были ли элементы фактически добавлены.Начальная емкость по умолчанию
ArrayList
довольно мала (10 из Java 1.4 - 1.8). Но поскольку базовая реализация представляет собой массив, размер массива должен быть изменен, если вы добавите много элементов. Чтобы избежать высокой стоимости изменения размера, когда вы знаете, что собираетесь добавить много элементов, создайтеArrayList
более высокую начальную емкость.источник
O(n/2)
илиO(n/4)
. Большая нотация O говорит вам, как операция масштабируется с большим n . и операция, требующаяn/2
этапов, масштабируется точно так же, как операция, требующаяn
этапов, что является причиной удаления постоянных слагаемых или факторов.O(n/2)
иO(n/4)
оба справедливыO(n)
.LinkedList
и вArrayList
любом случае иметь разные постоянные коэффициенты, поэтому не имеет смысла сравниватьO(n/2)
одно сO(n/4)
другим, оба обозначают операции линейного масштабирования.До сих пор, похоже, никто не обращал внимания на объем памяти каждого из этих списков, кроме общего консенсуса о том, что
LinkedList
«намного больше», чемArrayList
поэтому я сделал некоторое сжатие чисел, чтобы продемонстрировать, насколько точно оба списка занимают N пустых ссылок.Поскольку в их относительных системах ссылки бывают 32- или 64-битными (даже если они равны нулю), я включил 4 набора данных для 32- и 64-битных
LinkedLists
иArrayLists
.Примечание . Размеры, показанные для
ArrayList
линий, предназначены для усеченных списков. На практике емкость вспомогательного массиваArrayList
обычно больше, чем его текущее число элементов.Примечание 2: (спасибо BeeOnRope) Поскольку CompressedOops теперь используется по умолчанию начиная с середины JDK6 и выше, приведенные ниже значения для 64-битных машин будут в основном соответствовать их 32-битным аналогам, если, конечно, вы специально не отключите его.
Результат ясно показывает, что
LinkedList
это намного большеArrayList
, особенно с очень большим количеством элементов. Если память является фактором, держитесь подальшеLinkedLists
.Формулы, которые я использовал, следуют, дайте мне знать, если я сделал что-то не так, и я исправлю это. «b» - это 4 или 8 для 32- или 64-разрядных систем, а «n» - количество элементов. Обратите внимание, что причина для модов в том, что все объекты в java будут занимать кратное 8 байт пространство независимо от того, все они используются или нет.
ArrayList:
ArrayList object header + size integer + modCount integer + array reference + (array oject header + b * n) + MOD(array oject, 8) + MOD(ArrayList object, 8) == 8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8) + MOD(8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8), 8)
LinkedList:
LinkedList object header + size integer + modCount integer + reference to header + reference to footer + (node object overhead + reference to previous element + reference to next element + reference to element) * n) + MOD(node object, 8) * n + MOD(LinkedList object, 8) == 8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n + MOD(8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n, 8)
источник
int
4 или 8 байтов данных. В связанном списке есть, по сути, 4 «слова» накладных расходов. Таким образом, ваш график создает впечатление, что связанные списки используют «пять раз» хранилище списков массивов. Это не верно. Накладные расходы составляют 16 или 32 байта на объект, как аддитивная корректировка, а не коэффициент масштабирования.CompressedOops
теперь это значение по умолчанию во всех последних JDK (7, 8 и обновления 6 в течение нескольких лет), поэтому 64-разрядная версия не будет иметь значенияArrayList
илиLinkedList
размеров, если вы явно не отключили сжатые параметры для некоторая причина.ArrayList
без указания начальной емкости оно все равно будет использовать значительно меньше памяти, чем aLinkedList
.ArrayList
это то, что вы хотите.LinkedList
почти всегда ошибка (производительность).Почему
LinkedList
отстой:ArrayList
использовании.ArrayList
она, она все равно будет значительно медленнее.LinkedList
в источнике, потому что это, вероятно, неправильный выбор.источник
Как человек, который занимается проектированием производительности в очень крупномасштабных веб-сервисах SOA около десяти лет, я бы предпочел поведение LinkedList, а не ArrayList. Хотя постоянная пропускная способность LinkedList хуже и, следовательно, может привести к покупке большего количества оборудования, поведение ArrayList под давлением может привести к тому, что приложения в кластере будут расширять свои массивы почти синхронно, а для больших размеров массива может привести к отсутствию отзывчивости. в приложении и отключении, находясь под давлением, что является катастрофическим поведением.
Точно так же вы можете получить лучшую пропускную способность в приложении из стандартного сборщика мусора с пропускной способностью по умолчанию, но как только вы получите java-приложения с кучей 10 ГБ, вы можете заблокировать приложение на 25 секунд во время полного GC, что приводит к таймаутам и сбоям в приложениях SOA и дует ваши SLA, если это происходит слишком часто. Даже если сборщик CMS потребляет больше ресурсов и не достигает той же исходной пропускной способности, это гораздо лучший выбор, поскольку он имеет более предсказуемую и меньшую задержку.
ArrayList - лучший выбор для производительности, если все, что вы подразумеваете под производительностью, это пропускная способность и вы можете игнорировать задержки. По своему опыту на работе я не могу игнорировать задержку в худшем случае.
источник
LinkedList
всегда выделяет в пять раз больше памяти, чем простой массив ссылок, поэтомуArrayList
временно требующий 2,5 раза по-прежнему потребляет гораздо меньше памяти, даже если память не освобождается. Поскольку выделение большого массива обходит пространство Eden, они не оказывают никакого влияния на поведение GC, если только на самом деле не хватает памяти, в этом случаеLinkedList
взрыв произошел намного раньше…LinkedList
нужен только небольшой кусок свободной памяти, чтобы выделить для следующего элемента.ArrayList
потребуется большой и непрерывный свободный блок пространства для выделения массива с измененным размером. Если куча фрагментируется, то GC может в конечном итоге переупорядочить всю кучу только для того, чтобы освободить подходящий отдельный блок памяти.Алгоритмы: большие обозначения
ArrayLists хороши для записи один раз для чтения или добавления, но плохо подходят для добавления / удаления спереди или посередине.
источник
O(1)
. Он должен пройти через половину списка, чтобы найти точку вставки.LinkedList
- этоO(1)
если у вас есть итератор для позиции вставки , т.е.ListIterator.add
предположительноO(1)
для aLinkedList
.Да, я знаю, это древний вопрос, но я добавлю два моих цента:
LinkedList - почти всегда неправильный выбор с точки зрения производительности. Есть несколько очень специфических алгоритмов, для которых требуется LinkedList, но они очень, очень редки, и алгоритм обычно будет конкретно зависеть от способности LinkedList относительно быстро вставлять и удалять элементы в середине списка, как только вы перейдете туда с ListIterator.
Существует один общий случай использования, в котором LinkedList превосходит ArrayList: это очереди. Однако, если ваша цель - производительность, вместо LinkedList вы также должны рассмотреть возможность использования ArrayBlockingQueue (если вы можете заранее определить верхнюю границу размера очереди и можете позволить себе выделять всю память заранее) или эту реализацию CircularArrayList , (Да, это с 2001 года, поэтому вам нужно будет его обобщить, но я получил сопоставимые коэффициенты производительности с тем, что только что цитировалось в статье в недавней JVM)
источник
ArrayDeque
. docs.oracle.com/javase/6/docs/api/java/util/ArrayDeque.htmlArrayDeque
медленнее, чемLinkedList
если все операции находятся на одном конце. Это нормально, когда используется в качестве стека, но это не делает хорошую очередь.ArrayDeque
скорее всего будет быстрее, чемStack
при использовании в качестве стека, и быстрее, чемLinkedList
при использовании в качестве очереди.ArrayDeque
документации.Это вопрос эффективности.
LinkedList
быстр для добавления и удаления элементов, но медленный доступ к определенному элементу.ArrayList
быстро для доступа к определенному элементу, но может быть медленным, чтобы добавить к любому концу, и особенно медленно, чтобы удалить в середине.Массив vs ArrayList vs LinkedList vs Vector более детален, как и Linked List .
источник
Верно или неправильно: Пожалуйста, выполните тест на месте и решите сами!
Редактировать / Удалить быстрее,
LinkedList
чемArrayList
.ArrayList
, поддерживаемыйArray
, который должен быть вдвое больше, хуже в приложениях большого объема.Ниже приведен результат модульного теста для каждой операции. Время указывается в наносекундах.
Вот код:
источник
LinkedList
имеет намного больше памяти, потому что для каждого элемента есть объект узла с пятью полями. Во многих системах это занимает 20 байтов. Среднее количество служебной памяти на элемент для элементаArrayList
составляет полтора слова, что составляет 6 байтов, а в худшем - 8 байтов.removeIf(element -> condition)
там, где он подходит, что может быть значительно быстрее поArrayList
сравнению с циклом и удалением с помощью итератора, поскольку не требуется сдвигать весь остаток для каждого отдельного элемента. Работает ли это лучше или хуже, чемLinkedList
зависит от конкретного сценария, какLinkedList
теоретически O (1), но удаление только одного узла требует нескольких обращений к памяти, которые могут легко превысить число, необходимое дляArrayList
удаления при значительном количестве элементов ,ArrayList
это по сути массив.LinkedList
реализован в виде двойного связанного списка.Это
get
довольно ясно. O (1) дляArrayList
, потому чтоArrayList
разрешить произвольный доступ с помощью индекса. O (n) дляLinkedList
, потому что он должен сначала найти индекс. Примечание: есть разные версииadd
иremove
.LinkedList
быстрее в добавлении и удалении, но медленнее в получении. Вкратце,LinkedList
следует отдавать предпочтение, если:=== ArrayList ===
=== LinkedList ===
добавить (E e)
добавить (int индекс, E элемент)
Вот фигура из programcreek.com (
add
иremove
относится к первому типу, то есть добавляет элемент в конец списка и удаляет элемент в указанной позиции в списке.):источник
Джошуа Блох, автор LinkedList:
Ссылка: https://twitter.com/joshbloch/status/583813919019573248
Я прошу прощения за то, что я не настолько информативен, как другие ответы, но я подумал, что он будет самым интересным и не требующим пояснений.
источник
ArrayList
случайным образом доступен, в то времяLinkedList
как действительно дешево расширять и удалять элементы из. В большинстве случаевArrayList
это нормально.Если вы не создали большие списки и не измерили узкое место, вам, вероятно, никогда не придется беспокоиться о разнице.
источник
TL; DR, благодаря современной компьютерной архитектуре,
ArrayList
будет значительно более эффективным практически для любого возможного варианта использования - и поэтому егоLinkedList
следует избегать, за исключением некоторых очень уникальных и экстремальных случаев.В теории LinkedList имеет O (1) для
add(E element)
Также добавление элемента в середине списка должно быть очень эффективным.
Практика совсем иная, так как LinkedList - это структура данных Cache Hostile Data. От производительности POV - очень мало случаев, когда производительность
LinkedList
может быть выше, чем у Cache-friendlyArrayList
.Вот результаты тестового тестирования вставки элементов в случайных местах. Как вы можете видеть - список массива , если гораздо более эффективными, хотя теоретически каждая вставка в середине списка потребует «движения» в п поздних элементы массива (более низкие значения лучше):
Работа на оборудовании более позднего поколения (большие, более эффективные кэши) - результаты еще более убедительны:
LinkedList занимает гораздо больше времени, чтобы выполнить ту же работу. Источник Исходный код
Для этого есть две основные причины:
Главным образом - то, что узлы
LinkedList
разбросаны случайным образом по памяти. ОЗУ («Память с произвольным доступом») на самом деле не является случайным, и блоки памяти должны быть извлечены для кэширования. Эта операция занимает много времени, и когда такие выборки происходят часто - страницы памяти в кеше необходимо постоянно заменять -> Cache misses -> Cache неэффективен.ArrayList
элементы хранятся в непрерывной памяти - это именно то, для чего оптимизируется современная архитектура ЦП.Вторичное
LinkedList
требуется для удержания указателей назад / вперед, что означает 3-х кратное потребление памяти на одно сохраненное значение по сравнению сArrayList
.DynamicIntArray , кстати, является пользовательской реализацией ArrayList, содержащей
Int
(примитивный тип), а не Objects - следовательно, все данные действительно хранятся смежно - следовательно, еще более эффективно.Ключевым элементом, который следует помнить, является то, что стоимость выборки блока памяти является более значительной, чем стоимость доступа к одной ячейке памяти. Вот почему считыватель 1 МБ последовательной памяти работает в х400 раз быстрее, чем считывает этот объем данных из разных блоков памяти:
Источник: числа задержек, которые должен знать каждый программист
Просто чтобы сделать это еще более ясным, пожалуйста, проверьте эталон добавления элементов в начало списка. Это тот случай использования, в котором теоретически
LinkedList
должен действительно сиять иArrayList
давать плохие или даже худшие результаты:Примечание: это тест C ++ Std lib, но мой предыдущий опыт показал, что результаты C ++ и Java очень похожи. Исходный код
Копирование последовательных большой части памяти является операция оптимизируется современными процессорами - изменение теории и на самом деле делают, опять - таки,
ArrayList
/Vector
гораздо более эффективнымКредиты: Все опубликованные тесты созданы Kjell Hedström . Еще больше данных можно найти в его блоге
источник
Если в вашем коде есть
add(0)
иremove(0)
, используйте aLinkedList
и он красивееaddFirst()
иremoveFirst()
методы. В противном случае используйтеArrayList
.И, конечно же, Guma 's ImmutableList - ваш лучший друг.
источник
Я знаю, что это старый пост, но я, честно говоря, не могу поверить, что никто не упомянул, что
LinkedList
реализуетDeque
. Просто посмотрите на методы вDeque
(иQueue
); если вы хотите , сравнение справедливой, попробуйте запуститьLinkedList
противArrayDeque
и сделать функционально для-функции сравнения.источник
Вот запись Big-O в обоих
ArrayList
и ,LinkedList
а такжеCopyOnWrite-ArrayList
:ArrayList
LinkedList
CopyOnWrite-ArrayList
Исходя из этого, вы должны решить, что выбрать. :)
источник
LinkedList.add()
, хотя большинство ответов здесь говорят так.Давайте сравним LinkedList и ArrayList с параметрами ниже:
1. Реализация
2. Производительность
get (int index) или операция поиска
Причина, по которой ArrayList быстрее, чем LinkedList, заключается в том, что ArrayList использует систему на основе индекса для своих элементов, поскольку он внутренне использует структуру данных массива, с другой стороны,
LinkedList не предоставляет доступ к элементам на основе индекса, поскольку он выполняет итерацию с начала или до конца (в зависимости от того, что ближе), чтобы получить узел с указанным индексом элемента.
операция вставки () или добавления (объект)
удалить (int) операция
Операция удаления в LinkedList, как правило, такая же, как ArrayList, т.е. O (n).
3. Обратный Итератор
4. Начальная емкость
5. Объем памяти
Источник
источник
Я обычно использую одно над другим, исходя из сложности времени операций, которые я выполняю над этим конкретным списком.
источник
В дополнение к другим хорошим аргументам выше, вы должны заметить,
ArrayList
реализуетRandomAccess
интерфейс, в то время какLinkedList
реализуетQueue
.Таким образом, они как-то решают несколько иные проблемы, с разницей в эффективности и поведении (см. Их список методов).
источник
Это зависит от того, какие операции вы будете делать больше в списке.
ArrayList
быстрее получить доступ к индексированному значению. Гораздо хуже при вставке или удалении объектов.Чтобы узнать больше, прочитайте любую статью, в которой говорится о разнице между массивами и связанными списками.
источник
Список массивов - это, по сути, массив с методами для добавления элементов и т. Д. (Вместо этого следует использовать общий список). Это набор элементов, к которым можно получить доступ через индексатор (например, [0]). Это подразумевает переход от одного предмета к другому.
Связанный список определяет переход от одного элемента к следующему (Элемент a -> элемент b). Вы можете получить тот же эффект со списком массивов, но связанный список абсолютно говорит, какой элемент должен следовать за предыдущим.
источник
См. Учебные руководства по Java - список реализаций .
источник
Важной особенностью связанного списка (который я не читал в другом ответе) является объединение двух списков. Для массива это O (n) (+ накладные расходы на некоторые перераспределения), для связанного списка это только O (1) или O (2) ;-)
Важно : для Java
LinkedList
это не так! См. Существует ли быстрый метод concat для связанного списка в Java?источник
next
один список первому узлу второго списка. Единственный способ - использоватьaddAll()
последовательное добавление элементов, хотя это и лучше, чем циклически проходить и вызыватьadd()
каждый элемент. Чтобы сделать это быстро в O (1), вам нужен класс композитинга (например, org.apache.commons.collections.collection.CompositeCollection), но тогда это будет работать для любого вида List / Collection.ArrayList и LinkedList имеют свои плюсы и минусы.
ArrayList использует непрерывный адрес памяти по сравнению с LinkedList, который использует указатели на следующий узел. Поэтому, когда вы хотите найти элемент в ArrayList, это быстрее, чем делать n итераций с LinkedList.
С другой стороны, вставка и удаление в LinkedList намного проще, потому что вам просто нужно изменить указатели, тогда как ArrayList подразумевает использование операции сдвига для любой вставки или удаления.
Если у вас есть частые операции поиска в вашем приложении, используйте ArrayList. Если вы часто вставляете и удаляете, используйте LinkedList.
источник
Я прочитал ответы, но есть один сценарий, в котором я всегда использую LinkedList вместо ArrayList, которым я хочу поделиться, чтобы услышать мнения:
Каждый раз, когда у меня был метод, который возвращает список данных, полученных из БД, я всегда использую LinkedList.
Мое обоснование состояло в том, что, поскольку невозможно точно знать, сколько результатов я получаю, память не будет потрачена впустую (как в ArrayList с разницей между емкостью и фактическим количеством элементов), и не будет потрачено впустую время, пытаясь продублируйте емкость.
Что касается ArrayList, я согласен, что, по крайней мере, вы всегда должны использовать конструктор с начальной емкостью, чтобы минимизировать дублирование массивов в максимально возможной степени.
источник
ArrayList
иLinkedList
оба орудияList interface
и их методы и результаты почти идентичны. Однако между ними мало различий, которые делают одно лучше другого в зависимости от требования.ArrayList против LinkedList
1)
Search:
ArrayList
операция поиска довольно быстрая по сравнению сLinkedList
операцией поиска.get(int index)
вArrayList
дает производительность,O(1)
аLinkedList
производительность естьO(n)
.Reason:
ArrayList
поддерживает индексную систему для своих элементов, так как она неявно использует структуру данных массива, что ускоряет поиск элемента в списке. На другой сторонеLinkedList
реализует двусвязный список, который требует обхода всех элементов для поиска элемента.2)
Deletion:
LinkedList
операция удаления даетO(1)
производительность, аArrayList
дает переменную производительность:O(n)
в худшем случае (при удалении первого элемента) иO(1)
в лучшем случае (при удалении последнего элемента).Причина: каждый элемент LinkedList поддерживает два указателя (адреса), которые указывают на оба соседних элемента в списке. Следовательно, удаление требует только изменения местоположения указателя в двух соседних узлах (элементах) узла, который будет удален. В то время как в ArrayList все элементы должны быть сдвинуты, чтобы заполнить пространство, созданное удаленным элементом.
3)
Inserts Performance:
LinkedList
метод add даетO(1)
производительность, а в худшем -ArrayList
даетO(n)
. Причина та же, что и для удаления.4)
Memory Overhead:
ArrayList
поддерживает индексы и данные элемента, в то же времяLinkedList
поддерживает данные элемента и два указателя для соседних узловМежду этими классами есть несколько общих черт:
iterator
иlistIterator
классы возвращаются и возвращаютсяfail-fast
(если список структурно изменяется в любое время после создания итератора, любым способом, кроме как черезiterator’s
собственные методы удаления или добавления, итератор будетthrow
aConcurrentModificationException
).Когда использовать LinkedList, а когда использовать ArrayList?
(O(1))
поLinkedList
сравнению сArrayList(O(n))
.get method
Операции поиска ( ) выполняются быстро,Arraylist (O(1))
но не вLinkedList (O(n))
источник
Операция get (i) в ArrayList выполняется быстрее, чем LinkedList, потому что:
ArrayList: реализация массива изменяемого размера интерфейса List
LinkedList: реализация двусвязного списка интерфейсов List и Deque
Операции, которые индексируют в списке, будут проходить по списку с начала или конца, в зависимости от того, что ближе к указанному индексу.
источник
1) Базовая структура данных
Первое различие между ArrayList и LinkedList связано с тем, что ArrayList поддерживается Array, а LinkedList поддерживается LinkedList. Это приведет к дальнейшим различиям в производительности.
2) LinkedList реализует Deque
Еще одно различие между ArrayList и LinkedList состоит в том, что помимо интерфейса List, LinkedList также реализует интерфейс Deque, который обеспечивает операции first-first-out для add () и poll () и некоторых других функций Deque. 3) Добавление элементов в ArrayList Добавление элемента в ArrayList - это операция O (1), если он не вызывает изменение размера массива, в этом случае он становится O (log (n)), с другой стороны, добавление элемента в LinkedList - это операция O (1), так как она не требует навигации.
4) Удаление элемента из позиции
Чтобы удалить элемент из определенного индекса, например, вызвав remove (index), ArrayList выполняет операцию копирования, которая приближает его к O (n), в то время как LinkedList необходимо перейти к этой точке, что также делает его O (n / 2) , так как он может перемещаться в любом направлении на основе близости.
5) Итерации по ArrayList или LinkedList
Итерация - это операция O (n) для LinkedList и ArrayList, где n - это номер элемента.
6) Извлечение элемента из позиции
Операция get (index) - это O (1) в ArrayList, а O (n / 2) в LinkedList, так как она должна проходить до этой записи. Тем не менее, в обозначении Big O O (n / 2) - это просто O (n), потому что мы игнорируем там константы.
7) Память
LinkedList использует объект-оболочку Entry, который является статическим вложенным классом для хранения данных и двух узлов следующего и предыдущего, в то время как ArrayList просто хранит данные в массиве.
Таким образом, в случае ArrayList требования к памяти кажутся меньшими, чем в LinkedList, за исключением случая, когда Array выполняет операцию изменения размера, когда копирует содержимое из одного массива в другой.
Если массив достаточно большой, он может занять много памяти в этот момент и запустить сборку мусора, что может замедлить время отклика.
Из всех вышеупомянутых различий между ArrayList и LinkedList, похоже, что ArrayList - лучший выбор, чем LinkedList, почти во всех случаях, за исключением случаев, когда вы выполняете частую операцию add (), а не remove () или get ().
Связанный список легче изменить, чем ArrayList, особенно если вы добавляете или удаляете элементы из начала или конца, потому что связанный список внутренне хранит ссылки на эти позиции, и они доступны во время O (1).
Другими словами, вам не нужно проходить через связанный список, чтобы достичь позиции, в которую вы хотите добавить элементы, в этом случае добавление становится операцией O (n). Например, вставка или удаление элемента в середине связанного списка.
По моему мнению, используйте ArrayList поверх LinkedList для большинства практических целей в Java.
источник
Один из тестов, которые я видел здесь, проводит тест только один раз. Но я заметил, что вам нужно запускать эти тесты много раз, и в конечном итоге их время будет сходиться. По сути, JVM нужно разогреть. Для моего конкретного случая использования мне нужно было добавить / удалить элементы в список, который увеличивается примерно до 500 элементов. В моих тестах
LinkedList
получилось быстрее:LinkedList
около 50 000 н.с. иArrayList
около 90 000 н.с. Смотрите код ниже.источник
Оба метода remove () и insert () имеют эффективность времени выполнения O (n) для ArrayLists и LinkedLists. Однако причина времени линейной обработки обусловлена двумя очень разными причинами:
В ArrayList вы получаете доступ к элементу в O (1), но на самом деле удаление или вставка чего-либо делает его O (n), потому что все следующие элементы должны быть изменены.
В LinkedList для достижения необходимого элемента требуется O (n), потому что мы должны начинать с самого начала, пока не достигнем желаемого индекса. На самом деле удаление или вставка является константой, потому что нам нужно изменить только 1 ссылку для remove () и 2 ссылки для insert ().
Какой из этих двух способов быстрее вставить и удалить, зависит от того, где это происходит. Если мы ближе к началу, LinkedList будет быстрее, потому что нам нужно пройти через относительно немного элементов. Если мы ближе к концу, ArrayList будет быстрее, потому что мы добираемся туда за постоянное время и должны изменить только несколько оставшихся элементов, следующих за ним. Когда сделано точно в середине, LinkedList будет быстрее, потому что прохождение n элементов быстрее, чем перемещение n значений.
Бонус: хотя нет никакого способа сделать эти два метода O (1) для ArrayList, на самом деле есть способ сделать это в LinkedLists. Допустим, мы хотим пройтись по всему списку, удаляя и вставляя элементы на нашем пути. Обычно вы начинаете с самого начала для каждого элемента, используя LinkedList, мы также можем «сохранить» текущий элемент, над которым мы работаем, с помощью итератора. С помощью Итератора мы получаем эффективность O (1) для remove () и insert () при работе в LinkedList. Делая это единственным преимуществом в производительности, я знаю, что LinkedList всегда лучше, чем ArrayList.
источник
ArrayList расширяет AbstractList и реализует интерфейс List. ArrayList - это динамический массив.
Можно сказать, что он был в основном создан для преодоления недостатков массивов.
Класс LinkedList расширяет AbstractSequentialList и реализует интерфейсы List, Deque и Queue.
Производительность
arraylist.get()
- O (1), тогдаlinkedlist.get()
как O (n)arraylist.add()
- O (1),linkedlist.add()
0 (1)arraylist.contains()
- O (n),linkedlist.contains()
O (n)arraylist.next()
- O (1) иlinkedlist.next()
O (1)arraylist.remove()
- O (n) тогда какlinkedlist.remove()
O (1)В Arraylist
iterator.remove()
является O (n),тогда как В связанный список
iterator.remove()
O (1)источник