Big O из массивов JavaScript

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

Какую производительность (с точки зрения большой сложности времени O) можно ожидать от реализации JavaScript в отношении производительности массива?

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

  • Доступ - O (1)
  • Добавление - O (n)
  • Prepending - O (n)
  • Вставка - O (n)
  • Удаление - O (n)
  • Подкачка - O (1)

JavaScript позволяет предварительно заполнить массив до определенного размера, используя синтаксис new Array(length). (Бонусный вопрос: Является ли создание массива таким образом O (1) или O (n)). Это больше похоже на обычный массив и, если он используется в качестве массива с предварительным размером, может допускать добавление O (1). Если добавлена ​​циклическая буферная логика, вы можете достичь O (1). Если используется динамически расширяющийся массив, O (log n) будет средним случаем для обоих.

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

P.S.

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

Ответ 1

В отличие от большинства языков, которые реализуют массивы с массивами Javascript, а массивы Javascript Array являются объектами, а значения хранятся в хеш-таблице, как и обычные значения объекта. Таким образом:

  • Доступ - O (1)
  • Append - Amortized O (1) (иногда требуется изменить размер хеш-таблицы, обычно требуется только вставка)
  • Prepending - O (n) через unshift, поскольку для этого требуется переназначить все индексы
  • Вставка - Амортизация O (1), если значение не существует. O (n), если вы хотите сдвинуть существующие значения (например, используя splice).
  • Deletion - Amortized O (1), чтобы удалить значение O (n), если вы хотите переназначить индексы с помощью splice.
  • Подкачка - O (1)

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

Ответ 2

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