Примечание (из комментариев): книга, о которой идет речь, Структуры данных и алгоритмы на Python Гудрича, Тамассии и Гольдвассера , и вопросы о страницах с 202 по 204.
Если вы посмотрите на полное определение insert
из книги, это имеет больше смысла.
def insert(self, k, value):
if self.n == self.capacity:
self.resize(2 * self.capacity)
for j in range(self.n, k, −1):
self.A[j] = self.A[j−1]
self.A[k] = value
self.n += 1
Первая строка подразумевает, что self.n
- это количество элементов и соответствует индексу за концом, что означает, что для пользователя списка доступ к нему по этому индексу будет ошибочным. Но этот код принадлежит списку, и поскольку он имеет емкость в дополнение к размеру, он может использовать self.A[n]
, если self.n < self.capacity
(что верно при запуске цикла for).
Цикл просто перемещает последний элемент (с индексом n-1
) к следующему пространству в памяти, которое выходит за пределы для пользователя, но не для внутреннего использования. В конце n
увеличивается, чтобы отразить новый размер, а n-1
становится индексом того «следующего пространства в памяти», которое теперь содержит последний элемент.
Что касается временной сложности различных операций: ну, они не являются неправильными. Даже если O(n+1) = O(n)
, вы все равно можете написать O(n+1)
, если хотите, и в некоторых случаях это может быть более "точным".
Например, написано, что data.index(value)
имеет сложность O(k+1)
, с k
индексом искомого значения. Ну, если это значение в самом начале, тогда k = 0
, а сложность O(0+1) = O(1)
. И это правда: если вы всегда ищете значение, которое, как вы знаете, находится в самом начале, даже если эта операция бессмысленна, она имеет постоянную сложность по времени. Если бы вы изначально написали O(k)
вместо этого, то вы бы получили O(0)
за эту последнюю операцию, которую я никогда не видел, но я бы подумал, что операция мгновенная.
То же самое происходит с нарезкой: они, вероятно, написали O(k−j+1)
, потому что если вы берете только один элемент, то j = k
и сложность составляет O(1)
вместо O(0)
.
Обратите внимание, что временная сложность обычно определяется не с точки зрения фактических индексов конкретного применения функции, а с точки зрения общего количества элементов в контейнере, в котором используется функция. Вы можете думать об этом как о средней сложности использования функции со всеми возможными индексами, которая в случаях index
и нарезки просто равна O(n)
.