Найти тему
ZDG

Задача спирального заполнения матрицы на Python #2: Первая реализация

Оглавление

Это продолжение. Начало здесь: Подготовка

Для решения задачи напрашиваетcя элементарная логика: заполнить в цикле первую строку матрицы, а потом... а потом посмотрим. Давайте начнём:

for x in range(N): a[0][x] = x + 1

Обращение к a[0] даёт нам первую строку матрицы, а обращение к a[0][x] даёт нам элемент со смещением x в этой строке. Этому элементу мы присваиваем значение x + 1, так как элементы считаются с 0, а их значения – с 1.

Мы получим следующий результат:

[1, 2, 3, 4, 5]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]

Теперь нужно заполнить вертикальный столбец справа. Напишем ещё один цикл:

for y in range(N): a[y][N-1] = N + y

Теперь цикл двигается не по х, а по y, и значит, мы перебираем не столбцы, а строки, обращаясь в них к столбцу со смещением N-1:

[1, 2, 3, 4, 5]
[0, 0, 0, 0, 6]
[0, 0, 0, 0, 7]
[0, 0, 0, 0, 8]
[0, 0, 0, 0, 9]

Теперь нужно заполнить нижнюю строку, двигаясь справа налево, а затем первый столбец, двигаясь снизу вверх. Так мы полностью замкнем первый виток спирали:

Но есть проблемы:

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

Разобьём (мысленно, конечно) края матрицы на более подходящие отрезки и заодно посмотрим, какие для них нужно выбирать координаты и направления:

-2

Циклы теперь имеют одну и ту же длину, которая всегда выражается в N-1. У каждого угла есть свои координаты, которые также задаются через N. Наконец, заведём переменную, в которой будем накапливать значение натурального ряда.

c = 1
for x in range(N-1): a[0][x] = c; c += 1
for y in range(N-1): a[y][N-1] = c; c += 1
for x in range(N-1): a[N-1][N-1-x] = c; c += 1
for y in range(N-1): a[N-1-y][0] = c; c += 1

Мы получили такой результат:

-3

Осталось продолжать писать циклы, чтобы заполнить всю матрицу. Но сколько циклов писать, если N – произвольно заданное число? Давайте посмотрим, что получается, когда мы обошли матрицу по периметру 1 раз:

-4

Если отбросить периметр, то в центре остаётся незаполненная матрица размером N-2 * N-2, которую мы можем точно так же заполнять по периметру. Затем опять отбросить периметр, перейти к внутренней матрице размером N-4 * N-4, и так до тех пор, пока оставшаяся матрица не станет размером 1*1.

Иначе говоря, четыре вышеуказанных цикла мы повторяем, постоянно задавая новый старт внутри матрицы и уменьшая начальный размер N на 2. Мы дойдём от угла матрицы до её центра по диагонали за N/2 шагов, значит, столько раз и нужно повторить наши циклы.

Вот полный код:

Если не помещается полностью, смотрите по ссылке.

Комментарии к коду:

  • переменная start задаёт отступ от внешнего края оригинальной матрицы. Этот отступ увеличивается на 1 каждый раз, когда прогоняются 4 цикла по периметру.
  • N // 2 это целочисленное деление на 2.
  • N % 2 это остаток от деления на 2. Если N – нечётное число, то в центре останется пустая клетка, которую циклы заполнить не смогут. Её мы заполняем отдельно.
  • Вывод на печать делаем ленивый: проходим циклом по строкам матрицы и выводим каждую строку с помощью print, не заморачиваясь форматированием.

Это первый способ решения.

Следующая часть: Вторая и моя реализации