Когда использовать связанный список по списку массива/массива?

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

Ответ 1

Связанные списки предпочтительнее массивов, когда:

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

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

  3. вам не нужен произвольный доступ к любым элементам

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

Массивы предпочтительнее, когда:

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

  2. Вы заранее знаете количество элементов в массиве, чтобы вы могли выделить правильный объем памяти для массива.

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

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

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

Ответ 2

Массивы имеют O (1) случайный доступ, но очень дорого добавлять материал или удалять вещи из.

Связанные списки действительно дешевы для добавления или удаления элементов в любом месте и для повтора, но произвольный доступ - O (n).

Ответ 3

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

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

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

Ответ 4

Algorithm           ArrayList   LinkedList
seek front            O(1)         O(1)
seek back             O(1)         O(1)
seek to index         O(1)         O(N)
insert at front       O(N)         O(1)
insert at back        O(1)         O(1)
insert after an item  O(N)         O(1)

ArrayLists хороши для write-once-read-many или appenders, но плохо при добавлении/удалении спереди или в середине.

Ответ 5

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

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

Ответ 6

Это наиболее распространенные реализации Collection.

ArrayList:

  • Вставить/удалить в конце вообще O (1) наихудший случай O (n)

  • Вставить/удалить в середине O (n)

  • получить любую позицию O (1)

LinkedList

  • Вставить/удалить в любой позиции O (1) (обратите внимание, если у вас есть ссылка на элемент)

  • извлекается в середине O (n)

  • извлечь первый или последний элемент O (1)

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

HashMap

Вставить/удалить/извлечь ключ в O (1)

TreeSet insert/delete/содержит в O (log N)

HashSet вставить/удалить/содержит/размер в O (1)

Ответ 7

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

  • Поиск

Поскольку массив представляет собой структуру данных, основанной на индексе, поиск array.get(index) будет принимать O (1) раз, в то время как связанный список не является индексом DS, поэтому вам нужно пройти по индексу, где index <= n, n - размер связанного списка, поэтому массив имеет более быстрый связанный список при случайном доступе элементов.

Q.Какая красота за этим?

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

  • Вставка

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

  • Удаление

Он работает как вставки и лучше в LinkedList, чем в массиве.

Ответ 8

Хмм, Arraylist можно использовать в следующих случаях, как я полагаю:

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

Например, вам нужно импортировать и получать доступ ко всем элементам в списке контактов (размер которых неизвестен вам)

Ответ 9

Использовать связанный список для Radix Сортировать по массивам и для полиномиальных операций.

Ответ 10

1) Как объяснялось выше, операции вставки и удаления дают хорошую производительность (O (1)) в LinkedList по сравнению с ArrayList (O (n)). Следовательно, если в приложении есть требование частого добавления и удаления, тогда LinkedList - лучший выбор.

2) Операции поиска (get method) выполняются быстро в Arraylist (O (1)), но не в LinkedList (O (n)), так что если операций с добавлением и удалением меньше и больше запросов на поиск, ArrayList будет вашим лучший выбор.

Ответ 11

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

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

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

Когда вы часто вставляете или удаляете в конце списка, массивы предпочтительнее, потому что сложность будет o (1), переиндексация не требуется, но для связанного списка это будет o (n), потому что вам нужно идти от головы до последней node.

Я думаю, что поиск в обоих связанных списках и массивах будет o (log n), потому что вы, вероятно, будете использовать двоичный поиск.

Ответ 12

Я сделал некоторый бенчмаркинг и обнаружил, что класс списка на самом деле быстрее, чем LinkedList для случайной вставки:

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = 20000;
            Random rand = new Random(12345);

            Stopwatch watch = Stopwatch.StartNew();
            LinkedList<int> ll = new LinkedList<int>();
            ll.AddLast(0);
            for (int i = 1; i < count; i++)
            {
                ll.AddBefore(ll.Find(rand.Next(i)),i);

            }
            Console.WriteLine("LinkedList/Random Add: {0}ms", watch.ElapsedMilliseconds);

            watch = Stopwatch.StartNew();
            List<int> list = new List<int>();
            list.Add(0);
            for (int i = 1; i < count; i++)
            {
                list.Insert(list.IndexOf(rand.Next(i)), i);

            }
            Console.WriteLine("List/Random Add: {0}ms", watch.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

Для связанного списка требуется 900 мс и 100 мс для класса списка.

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

Ответ 13

В действительности локальность памяти оказывает огромное влияние на производительность при реальной обработке.

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

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