Можно ли удалить рекурсию из этой функции?
Вопрос
Я уже некоторое время играю с этим и просто не вижу очевидного решения.Я хочу удалить рекурсию из функции XinY_Go.
def XinY_Go(x,y,index,slots):
if (y - index) == 1:
slots[index] = x
print slots
slots[index] = 0
return
for i in range(x+1):
slots[index] = x-i
XinY_Go(x-(x-i), y, index + 1, slots)
def XinY(x,y):
return XinY_Go(x,y,0,[0] * y)
Функция вычисляет количество способов поместить X шариков в Y слотов.Вот несколько примеров выходных данных:
>>> xy.XinY(1,2) [1, 0] [0, 1] >>> xy.XinY(2,3) [2, 0, 0] [1, 1, 0] [1, 0, 1] [0, 2, 0] [0, 1, 1] [0, 0, 2]
Решение
Наивная реализация Предложение @Joel Coehoorn от Joel Coehoorn следует:
def XinY_Stack(x, y):
stack = [(x, 0, [0]*y)]
while stack:
x, index, slots = stack.pop()
if (y - index) == 1:
slots[index] = x
print slots
slots[index] = 0
else:
for i in range(x + 1):
slots[index] = x-i
stack.append((i, index + 1, slots[:]))
Пример:
>>> XinY_Stack(2, 3)
[0, 0, 2]
[0, 1, 1]
[0, 2, 0]
[1, 0, 1]
[1, 1, 0]
[2, 0, 0]
Основанный на itertools.product
def XinY_Product(nmarbles, nslots):
return (slots
for slots in product(xrange(nmarbles + 1), repeat=nslots)
if sum(slots) == nmarbles)
Основанный на вложенных циклах
def XinY_Iter(nmarbles, nslots):
assert 0 < nslots < 22 # 22 -> too many statically nested blocks
if nslots == 1: return iter([nmarbles])
# generate code for iter solution
TAB = " "
loopvars = []
stmt = ["def f(n):\n"]
for i in range(nslots - 1):
var = "m%d" % i
stmt += [TAB * (i + 1), "for %s in xrange(n - (%s)):\n"
% (var, '+'.join(loopvars) or 0)]
loopvars.append(var)
stmt += [TAB * (i + 2), "yield ", ','.join(loopvars),
', n - 1 - (', '+'.join(loopvars), ')\n']
print ''.join(stmt)
# exec the code within empty namespace
ns = {}
exec(''.join(stmt), ns, ns)
return ns['f'](nmarbles + 1)
Пример:
>>> list(XinY_Product(2, 3))
[(0, 0, 2), (0, 1, 1), (0, 2, 0), (1, 0, 1), (1, 1, 0), (2, 0, 0)]
>>> list(XinY_Iter(2, 3))
def f(n):
for m0 in xrange(n - (0)):
for m1 in xrange(n - (m0)):
yield m0,m1, n - 1 - (m0+m1)
[(0, 0, 2), (0, 1, 1), (0, 2, 0), (1, 0, 1), (1, 1, 0), (2, 0, 0)]
Другие советы
Все, что мы считаем рекурсией, также можно рассматривать как проблему, основанную на стеке, где рекурсивная функция просто использует стек вызовов программы, а не создает отдельный стек. Это означает, что любая рекурсивная функция может быть переписана с использованием стека. Р>
Я не знаю Python достаточно хорошо, чтобы дать вам реализацию, но это должно указать вам правильное направление. Но вкратце, поместите начальные аргументы функции в стек и добавьте цикл, который выполняется, пока размер стека больше нуля. Сдавайте один раз за итерацию цикла, нажимайте каждый раз, когда функция вызывает себя сама. Р>
Посмотрите на этот код для создания всех перестановок, я думаю, мне было бы относительно просто реализовать нечто подобное для вашей проблемы.