Я обучение себе алгоритмы. Мне нужно было поменять два элемента в списке. Python упрощает все:
def swap(A, i, j):
A[i], A[j] = A[j], A[i]
Это работает:
>>> A = list(range(5))
>>> A
[0, 1, 2, 3, 4]
>>> swap(A, 0, 1)
>>> A
[1, 0, 2, 3, 4]
Обратите внимание, что функция устойчива к вырожденному случаю i = j
. Как и следовало ожидать, он просто оставляет список без изменений:
>>> A = list(range(5))
>>> swap(A, 0, 0)
>>> A
[0, 1, 2, 3, 4]
Позже я хотел переставить три элемента в списке. Я написал функцию, чтобы переставить их в 3-цикл:
def cycle(A, i, j, k):
A[i], A[j], A[k] = A[j], A[k], A[i]
Это сработало хорошо:
>>> A = list("tap")
>>> A
['t', 'a', 'p']
>>> cycle(A, 0, 1, 2)
>>> A
['a', 'p', 't']
Однако я (в конце концов) обнаружил, что он ошибочен в дегенеративных случаях. Я предположил, что вырожденный 3-цикл будет свопом. Таким образом, когда i = j
, cycle(i, i, k) ≡ swap(i, k)
:
>>> A = list(range(5))
>>> cycle(A, 0, 0, 1)
>>> A
[1, 0, 2, 3, 4]
Но когда i = k
происходит что-то еще:
>>> A = list(range(5))
>>> sum(A)
10
>>> cycle(A, 1, 0, 1)
>>> A
[1, 1, 2, 3, 4]
>>> sum(A)
11
Что происходит? sum
должен быть инвариантным относительно любой перестановки! Почему этот случай i = k
вырождается по-разному?
Как я могу достичь того, чего хочу? Это функция с тремя циклами, которая вырождается в swap, если только 2 индекса различны cycle(i, i, j) ≡ cycle(i, j, i) ≡ cycle(i, j, j) ≡ swap(i, j)