Массив против связанного списка

зачем кому-то использовать связанный список с помощью массива?

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

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

этот вопрос не дубликат этот вопрос потому что другой вопрос задает конкретно о конкретном классе Java, в то время как этот вопрос касается общих структур данных.

30 ответов


  • проще хранить данные разных размеров в связанном списке. Массив предполагает, что каждый элемент имеет одинаковый размер.
  • Как вы упомянули, для связанного списка легче расти органично. Размер массива должен быть известен заранее, или повторно, когда она должна расти.
  • перетасовка связанного списка-это просто вопрос изменения того, что указывает на то, что. Перетасовка массива сложнее и / или занимает больше памяти.
  • пока все ваши итерации происходят в контексте "foreach", вы не теряете производительности в итерации.

еще одна веская причина заключается в том, что связанные списки хорошо подходят для эффективных многопоточных реализаций. Причина этого в том, что изменения, как правило, локальны - затрагивают только один или два указателя для вставки и удаления в локализованной части структуры данных. Таким образом, вы можете иметь много потоков, работающих в одном связанном списке. Даже больше, возможно создать lock-free версии используя CAS-тип деятельности и во избежание тяжеловесные замки вполне.

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

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


Википедия имеет очень хороший раздел о различиях.

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

с другой стороны, массивы позволяют случайные доступ, в то время как связанные списки позволяют только последовательный доступ к элементам. Односвязные списки, по сути, могут только быть пройденным в одном направлении. Этот делает связанные списки непригодными для приложения, где полезно посмотреть элемента по его индексу быстро, такие как heapsort как. Последовательный доступ массивы также быстрее, чем на linked списки на многих машинах из-за местоположения кэшей ссылок и данных. Связанный списки получают почти никакой пользы от тайник.

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

http://en.wikipedia.org/wiki/Linked_list


Я добавлю еще-списки могут действовать как чисто функциональный структуры данных.

например, вы можете иметь совершенно разные списки, разделяющие один и тот же конечный раздел

a = (1 2 3 4, ....)
b = (4 3 2 1 1 2 3 4 ...)
c = (3 4 ...)

т. е.:

b = 4 -> 3 -> 2 -> 1 -> a
c = a.next.next  

без необходимости копировать данные, на которые указывает a на b и c.

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


объединение двух связанных списков (особенно двух дважды связанных списков) намного быстрее, чем объединение двух массивов (при условии, что слияние является разрушительным). Первый принимает O(1), второй принимает O (n).

EDIT: чтобы уточнить, я имел в виду" слияние " здесь в неупорядоченном смысле, а не как в сортировке слияния. Возможно, "сцепление" было бы более подходящим словом.


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

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


прежде всего, в связанных списках c++ не должно быть намного больше проблем для работы, чем с массивом. Вы можете использовать std:: list или увеличить список указатель для связанных списков. Ключевые проблемы со связанными списками и массивами-это дополнительное пространство, необходимое для указателей и ужасного случайного доступа. Вы должны использовать связанный список, если вы

  • вам не нужен случайный доступ к данным
  • вы будете добавлять/удалять элементы, особенно в середина списка

широко недооцененным аргументом для ArrayList и против LinkedList является то, что LinkedLists неудобно во время отладки. Время, затрачиваемое разработчиками обслуживания на понимание программы, например, на поиск ошибок, увеличивается, и IMHO иногда не оправдывает наносекунды в улучшении производительности или байты в потреблении памяти в корпоративных приложениях. Иногда (ну, конечно, это зависит от типа приложений), лучше потратить несколько байтов, но иметь применение, которое является более ремонтопригодным или легче понять.

например, в среде Java и с помощью отладчика Eclipse отладка ArrayList покажет очень простую для понимания структуру:

arrayList   ArrayList<String>
  elementData   Object[]
    [0] Object  "Foo"
    [1] Object  "Foo"
    [2] Object  "Foo"
    [3] Object  "Foo"
    [4] Object  "Foo"
    ...

С другой стороны, просмотр содержимого LinkedList и поиск конкретных объектов становится кошмаром для расширения дерева, не говоря уже о когнитивных накладных расходах, необходимых для фильтрации внутренних элементов LinkedList:

linkedList  LinkedList<String>
    header  LinkedList$Entry<E>
        element E
        next    LinkedList$Entry<E>
            element E   "Foo"
            next    LinkedList$Entry<E>
                element E   "Foo"
                next    LinkedList$Entry<E>
                    element E   "Foo"
                    next    LinkedList$Entry<E>
                    previous    LinkedList$Entry<E>
                    ...
                previous    LinkedList$Entry<E>
            previous    LinkedList$Entry<E>
        previous    LinkedList$Entry<E>

для меня это так,

  1. открыть

    • Связанные Списки допускают только последовательный доступ к элементам. Таким образом, алгоритмические сложности порядка O (n)
    • массивы разрешить случайный доступ к его элементам и, таким образом, сложность порядка O(1)
  2. для хранения

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

    • размер связанные списки динамичны по своей природе.
    • размер массив ограничен декларация.
  4. Вставка/Удаление

    • элементы могут быть вставлены и удалены связанные списки на неопределенный срок.
    • вставка/удаление значений массивы очень дорого. Это требует перераспределения памяти.

две вещи:

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

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

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

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

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

удаление элемента из списка легко, так как вам просто нужно сломать пару ссылок, а затем прикрепить их обратно вместе. Удаление элемента из вектора может быть быстрее или медленнее, в зависимости от того, заботитесь ли вы о заказе. Замена последнего элемента поверх элемента, который вы хотите удалить, происходит быстрее, в то время как смещение всего после него медленнее, но сохраняет порядок.


У Эрика Липперта недавно был в должности по одной из причин массивы следует использовать консервативно.


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


вот быстрый: удаление элементов быстрее.


Linked-list особенно полезны, когда коллекция постоянно растет и сокращается. Например, трудно представить себе попытку реализовать очередь (добавить в конец, удалить с фронта) с помощью массива-вы бы потратили все свое время, перемещая вещи вниз. С другой стороны, это тривиально со связанным списком.


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


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

в наши дни создание связанного списка-это просто упражнение для студентов, чтобы они могли понять концепцию. Вместо этого каждый использует заранее составленный список. В C++, основываясь на описании в нашем вопросе, это, вероятно, означает вектор stl (#include <vector> ).

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


Это действительно вопрос эффективности, накладные расходы на вставку, удаление или перемещение (где вы не просто меняете местами) элементов внутри связанного списка минимальны, т. е. сама операция O(1), стихи O(n) для массива. Это может иметь существенное значение, если вы активно работаете со списком данных. Вы выбрали типы данных, основываясь на том, как вы будете работать с ними, и выбрали наиболее эффективный для используемого алгоритма.


массивы имеют смысл, где точное количество элементов будет известно, и где поиск по индексу имеет смысл. Например, если бы я хотел сохранить точное состояние моего видеовыхода в данный момент без сжатия, я бы, вероятно, использовал массив размера [1024][768]. Это даст мне именно то, что мне нужно, и список будет намного медленнее, чтобы получить значение данного пикселя. В местах, где массив не имеет смысла, обычно существуют лучшие типы данных, чем список эффективно работать с данными.


Массивы Против Связанного Списка:

  1. выделение памяти массива иногда завершается ошибкой из-за фрагментированной памяти.
  2. кэширование лучше в массивах, так как всем элементам выделяется непрерывное пространство памяти.
  3. кодирование сложнее, чем массивы.
  4. нет ограничения размера в связанном списке, в отличие от массивов
  5. вставка / удаление быстрее в связанном списке, а доступ быстрее в массивах.
  6. связанный список лучше от многопоточности точка зрения.

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


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

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

ваша первая проблема, как вы сами отметили, - это вставка-связанный список позволяет вставлять в O(1), но массив обычно требует O(n). Эта проблема может быть частично преодолена - можно создать структуру данных, которая дает массив-подобный по порядку интерфейс доступа там и чтение и запись, в худшем-логарифмическая.

ваша вторая и более серьезная проблема заключается в том, что при заданном элементе нахождение следующего элемента равно O(n). Если набор не был изменен, вы можете сохранить индекс элемента в качестве ссылки вместо указателя, тем самым сделав операцию find-next операцией O(1), но поскольку это все, что у вас есть, это указатель на сам объект и нет способа определить его текущий индекс в массиве, кроме как путем сканирования всего "массива". Это непреодолимая проблема для массивов-даже если вы можете оптимизировать вставки, вы ничего не можете сделать для оптимизации операции поиска следующего типа.


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

-- больший вопрос в том, можем ли мы иметь гибрид обоих. Что-то вроде того, что python и perl реализуют как списки.


Список Ссылок

более предпочтительным, когда речь идет о вкладывании! В основном то, что делает, это то, что он имеет дело с указателем

1 -> 3 -> 4

"вставить" (2)

1........3......4
.....2

наконец-то

1 -> 2 -> 3 -> 4

одна стрелка из 2 точек на 3 и стрелка из 1 точки на 2

просто!

но из массива

| 1 | 3 | 4 |

"вставить" (2) | 1 | 3 | | 4 | | 1 | | 3 | 4 | | 1 | 2 | 3 | 4 |

Ну любой может визуализировать разницу! Всего за 4 индекса мы выполняем 3 шага

Что делать, если длина массива составляет один миллион? Эффективен ли массив? Ответ-нет! :)

то же самое касается удаления! В связанном списке мы можем просто использовать указатель и обнулить элемент и далее в классе объектов! Но для array нам нужно выполнить shiftLeft()

надеюсь, что это поможет! :)


связанный список больше накладных расходов для поддержания, чем массив, он также требует дополнительного хранения памяти все эти точки согласованы. Но есть несколько вещей, которые время не могу сделать. Во многих случаях предположим, что вам нужен массив длины 10^9, который вы не можете получить, потому что там должно быть одно постоянное место памяти. Связанный список может быть спасителем.

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

контейнеры STL обычно имеют реализацию связанного списка за сценой.


разница между ArrayList и LinkedList

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

ArrayList -

  1. ArrayList внутренне использует динамический массив для хранения элементы.

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

  3. ArrayList класс может выступать в качестве списка только потому, что он орудия List только.
  4. ArrayList лучше для хранения и доступ к данным.

LinkedList -

  1. LinkedList внутренне использует дважды связанный список для хранения элементов.

  2. манипуляции с LinkedList быстрее ArrayList потому что он использует дважды связанный список, поэтому в памяти не требуется смещение бит.

  3. LinkedList класс может выступать в качестве списка и очереди, поскольку он реализует List и интерфейсы Deque.

  4. LinkedList лучше для управления данными.


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

Disadvatige может быть, что указатели занимают много места.

и об этом кодировании сложнее: Обычно вам не нужен связанный с кодом список (или только один раз), в который они включены STL и это не так сложно, если вы все еще должны это сделать.


Я также думаю, что список ссылок лучше, чем массивы. потому что мы проходим в списке ссылок, но не в массивах


в зависимости от языка, некоторые из этих недостатков и преимуществ можно считать:

Язык Программирования C: при использовании связанного списка (как правило, через указатели структуры) особое внимание должно быть уделено тому, что вы не утечка памяти. Как уже упоминалось ранее, связанные списки легко перетасовать, потому что все, что мы делаем, это изменение указателей, но мы будем помнить, чтобы освободить все?

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


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

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

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

Если у вас действительно большой массив, вы можете объединить его с другим, гораздо меньшим массивом или связанным списком, где меньший содержит 20, 50, 100 последних использованных элементов. Если нужный не находится в более коротком связанном списке или массиве, перейдите к большому массиву. Если вы нашли там, вы можете добавить его в меньший связанный список / массив по предположению ,что "вещи, которые недавно использовались, наиболее похожи на повторное использование" (и да, возможно, натыкаясь на наименее недавно используемый элемент из списка ). Что верно во многих случаях и решило проблему, которую мне пришлось решать в an .Разрешения безопасности ASP проверяя модуль, с легкостью, элегантностью и впечатляющей скоростью.


в то время как многие из вас коснулись major adv./dis связанного списка против массива, большинство сравнений-это то, как один лучше/ хуже другого.Например. вы можете сделать случайный доступ в массиве, но не возможно в связанном списке и других. Однако это предполагает, что списки ссылок и массив будут применяться в аналогичном приложении. Однако правильным ответом должно быть то, как список ссылок будет предпочтительнее массива и наоборот в конкретном развертывании приложения. Предположим, вы хотите реализовать словарь приложение, что бы вы использовали ? Массив: МММ, это позволит легко получить через двоичный поиск и другой поиск algo .. но давайте подумаем, как список ссылок может быть лучше..Скажем, вы хотите найти "Blob" в словаре. Имеет ли смысл иметь список ссылок A->B->C->D--- - >Z, а затем каждый элемент списка также указывает на массив или другой список всех слов, начинающихся с этой буквы ..

A -> B -> C -> ...Z
|    |    |
|    |    [Cat, Cave]
|    [Banana, Blob]
[Adam, Apple]

теперь вышеуказанный подход лучше или плоский массив [Адам, Яблоко, Банан, Капля, Кошка, Пещера]? Возможно ли это вообще с array ? Таким образом, основным преимуществом списка ссылок является то, что элемент может указывать не только на следующий элемент, но и на другой список ссылок/массив/ кучу/ или любое другое место памяти. Массив является одной плоской contigous памяти нарезанный в размер блоков элементов будут сохранены.. Список ссылок, с другой стороны, представляет собой куски несмежных блоков памяти (может быть любого размера и может хранить что угодно) и указывать друг на друга вы хотите. Аналогично, скажем, вы делаете USB-накопитель. Теперь вы хотите, чтобы файлы были сохранены как любой массив или как список ссылок ? Я думаю, вы понимаете, на что я указываю:)