Выполнение списка (...). Insert (...)

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

from bisect import bisect
index = bisect(x, a)      # O(log n)  (also, shouldn't it be a standard list function?)
x.insert(index, a)        # O(1) + memcpy()

который принимает log n, плюс, если я правильно понимаю, операцию копирования памяти для x[index:]. Теперь я недавно прочитал, что узкое место обычно находится в связи между процессором и памятью, поэтому копия памяти может быть выполнена оперативной памятью довольно быстро. Как это работает?

Ответ 1

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

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

Для небольших списков операция bisect может занять больше времени, чем x.insert, даже если первый - O (log n), а последний - O (n). Однако для длинных списков я бы x.insert предположить, что x.insert является узким местом. В таких случаях вы должны рассмотреть возможность использования другой структуры данных.

Ответ 2

Используйте blist module, если вам нужен список с лучшей производительностью вставки.

Ответ 3

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

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