Можно ли удалить рекурсию из этой функции?

StackOverflow https://stackoverflow.com/questions/616416

  •  03-07-2019
  •  | 
  •  

Вопрос

Я уже некоторое время играю с этим и просто не вижу очевидного решения.Я хочу удалить рекурсию из функции 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 достаточно хорошо, чтобы дать вам реализацию, но это должно указать вам правильное направление. Но вкратце, поместите начальные аргументы функции в стек и добавьте цикл, который выполняется, пока размер стека больше нуля. Сдавайте один раз за итерацию цикла, нажимайте каждый раз, когда функция вызывает себя сама.

Посмотрите на этот код для создания всех перестановок, я думаю, мне было бы относительно просто реализовать нечто подобное для вашей проблемы.

Как сгенерировать все перестановки списка в питон?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top