Комментарии 12
Я то к тому, то что вы написали не панацея, и не всегда может быть применена, лучше озаглавить «оптимизация рекурсивного алгоритма для задачи # .....»
Почему же не всегда? По-моему, очень общее решение. Главное помнить, что в функцию можно передавать не один аргумент, а вектор аргументов, из результатов всех предыдущих рекурсивных вызовов (или заглушек для последних N
вызовов, где N
— количество рекурсивных вызовов), а возвращать — те же аргументы, смещенные на одну позицию + новое значение. И тогда любую рекурсию можно развернуть. Во всяком случае мне не удается придумать контрпример.
Для взаимной рекурсии всегда можно сделать инлайнинг и получить одну рекурсивную функцию покрупнее.
def cost(s, cache=[0, 0]):
if s >= len(cache):
for i in range(len(cache), s + 2, 2):
c = cache[i // 2] + 1
cache += c, min(c + 1, 5)
return cache[s]
Лучше бы Eric Lippert восхищался питоном молча.
Как-то сделал модуль, с которым можно рекурсивные вызовы поменять на yield
и поменять return
на raise StopIteration(...)
, а он бы под капотом остановленные генераторы в стек складывал.
def sumrange(x):
if x == 0:
return 0
r = sumrange(x - 1)
return x + r
print(sumrange(10)) # 55
print(sumrange(1000))
# RecursionError: maximum recursion depth exceeded
from precursion import precurse
@precurse
def sumrange(x):
if x == 0:
raise StopIteration(0)
r = yield sumrange.r(x - 1)
raise StopIteration(x + r)
print(sumrange(1000)) # 500500!!1
https://github.com/python273/precursion (правда сломано в 3.7)
https://github.com/python273/precursion/blob/master/precursion/precursion.py#L28-L51
Устранение рекурсии в Python