Подтвердить что ты не робот

Разница между MutableList и ListBuffer

В чем разница между классами Scala MutableList и ListBuffer в scala.collection.mutable? Когда вы будете использовать один против другого?

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

4b9b3361

Ответ 1

Небольшое объяснение того, как они работают.

ListBuffer использует внутренне Nil и :: для создания неизменяемого List и позволяет удалять первый и последний элементы в постоянном времени. Для этого он удерживает указатель на первом и последнем элементе списка и на самом деле разрешается изменять заголовок и хвост класса (tt → , неизменяемого) (хороший трюк, разрешенный private[scala] var членами ::). Его метод toList возвращает постоянное неизменное значение List в постоянное время, так как он может напрямую возвращать внутреннюю структуру. Он также является построителем по умолчанию для неизменяемого List (и, следовательно, может быть разумно ожидаемо иметь постоянное добавление). Если вы вызываете toList, а затем снова добавляете элемент в буфер, он принимает линейное время относительно текущего количества элементов в буфере, чтобы воссоздать новую структуру, так как он больше не должен мутировать экспортированный список.

MutableList работает внутри с LinkedList вместо этого, (с открытым, а не как ::) изменчивой реализацией связанных списков, которая знает свой элемент и преемник (например, ::). MutableList также сохраняет указатели на первый и последний элементы, но toList возвращается в линейном времени, так как полученный List построен из LinkedList. Таким образом, ему не нужно повторно инициализировать буфер после экспорта List.

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

Мое предположение заключается в том, что в капитальном ремонте 2.8, MutableList предшествующем ListBuffer и всей системе Builder. Фактически, MutableList преимущественно полезен из пакета collection.mutable: он имеет метод private[mutable] def toLinkedList, который возвращается в постоянное время и поэтому может эффективно использоваться в качестве делегированного построителя для всех структур, которые поддерживают LinkedList внутренне.

Поэтому я также рекомендую ListBuffer, так как он может также привлечь внимание и оптимизацию в будущем, чем "чисто изменяемые" структуры, такие как MutableList и LinkedList.

Ответ 2

Это дает вам обзор характеристик производительности: http://www.scala-lang.org/docu/files/collections-api/collections.html; интересно, MutableList и ListBuffer там не отличаются. В документации MutableList говорится, что он используется внутренне как базовый класс для Stack и Queue, поэтому, возможно, ListBuffer является более официальным классом с точки зрения пользователя?

Ответ 3

Вам нужен список (почему список?), который является растёт и усаживается, и вы хотите постоянно добавлять и добавлять. Ну, Buffer, признак, имеет константу append и prepend, причем большинство других операций линейны. Я предполагаю, что ListBuffer, класс, реализующий Buffer, имеет постоянное время удаления первого элемента.

Итак, моя собственная рекомендация для ListBuffer.

Ответ 4

Сначала давайте рассмотрим некоторые из соответствующих типов в Scala

List - Неизменяемая коллекция. Рекурсивная реализация, т.е. i.e Экземпляр списка имеет два основных элемента: головка и хвост, где хвост ссылается на другой List.

List[T]
  head: T
  tail: List[T]  //recursive

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

Node[T]
  value: T
  next: Node[T]  //sequential

LinkedList[T]
  first: Node[T]

Список представляет собой функциональную структуру данных (неизменность) по сравнению с LinkedList, которая является более стандартной на императивных языках.

Теперь посмотрим

ListBuffer - реализация изменяемого буфера, поддерживаемая List.

MutableList - реализация на основе LinkedList (была бы более понятной, если бы она была названа LinkedListBuffer)

Они обе имеют одинаковые границы сложности для большинства операций.

Однако, если вы запрашиваете List из MutableList, тогда он должен преобразовать существующее линейное представление в рекурсивное представление, которое принимает O (n), что и указывает @Jean-Philippe Pellet. Но если вы запросите Seq из MutableList, то сложность - O (1).

Таким образом, ИМО выбор сужается до специфики вашего кода и ваших предпочтений. Хотя, я подозреваю, что есть намного больше List и ListBuffer.

Ответ 5

Обратите внимание, что ListBuffer является окончательным/закрытым, а вы можете расширить MutableList. В зависимости от вашего приложения расширяемость может быть полезна.