Циклический сдвиг списка. Язык программирования Python

preview_player
Показать описание
Циклический сдвиг как задача рассматривается по отношению к массивам. В самом Питоне, без подключения дополнительных модулей, такого типа данных, как массив, нет. Вместо этого есть список, который условно можно рассматривать как некий аналог массива. Однако сдвиг в нем может выполняться методами списка, а не теми алгоритмами, которые используются в других языках по отношению к настоящим массивам.
Что значит циклический сдвиг? Это значит, что значения элементов массива друг за другом меняют адреса своих ячеек. При сдвиге на один шаг вправо первое значение становится на место второго, второе на место третьего и так далее.
При этом у нас освобождается первая ячейка, а последнее значение как бы выбывает. Но если сдвиг, так сказать, кольцевой, то выбывшее значение уходит вперед и занимает первую ячейку.
Сдвиг может выполняться не только вправо, но и влево. В этом случае выбывают первые элементы. И потом они добавляются в конец.
Если сдвиг выполняется на несколько шагов, то мы фактически должны удалить срез с конца длинной, равной количеству шагов, и вставить его в начало списка.

Вспомним, что в Python элементы индексируются не только с начала, но и с конца. Так минус первый элемент – это последнее значение списка. Минус второй – предпоследнее значение.
Пользуясь индексацией с конца, можем взять срез из двух последних элементов. Если после двоеточия ничего не стоит, значит имеется в виду конец списка.
Чтобы извлечь все элементы кроме двух последних, надо взять срез от начала списка до минус второго. Здесь 0 можно опустить.
Таким образом, чтобы получить список, в котором элементы смещены на 2 вправо по отношению к исходному, мы можем сложить взятые срезы. Сначала берем срез с конца и добавляем к нему срез с начала.

В этой программе количество шагов циклического сдвига запрашивается у пользователя.
Но на самом деле никакого сдвига в исходном списке не происходит. Вместо этого из срезов создается новый список. В этом можно убедиться с помощью функции id. Она возвращает уникальный идентификатор объекта. Как мы видим он разный.
Кроме того, под цикличностью можно ведь понимать и то, что сдвиг на несколько шагов должен происходить постепенно. Сначала получаем массив, сдвинутый на один шаг, потом на второй и так далее.
В таком случае может быть удобнее пользоваться методами списка.
Нам понадобятся методы pop и insert. Первый без аргументов извлекает из списка последний элемент. С помощью метода insert мы можем вставить этот элемент в начало.

В цикле это будет выглядеть так. Сначала извлекаем последний элемент, затем добавляем его в нулевую позицию.
Обратите внимание, что мы имеем дело с тем же списком.
Если надо выводить список после каждого шага, то перенесем print(a) в тело цикла.

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

Рекомендации по теме
Комментарии
Автор

Большое спасибо за урок. Подскажите пожалуйста, а какая будет сложность по памяти у данного алгоритма O(n)?

trypophobia