Как правило, рекурсия создает Дерево вызовов, корень которого является исходным вызовом, а листья - вызовами, которые не рекурсируются.
Вырожденный случай - это когда каждый вызов выполняет только один другой вызов, в этом случае дерево вырождается в простой список. Преобразование в итерацию затем просто достигается с помощью стека, как продемонстрировал @ Jeremiah.
В более общем случае, как здесь, когда каждый вызов выполняет более (строго), чем один вызов. Вы получаете настоящее дерево, и поэтому есть несколько способов пройти его.
Если вы используете очередь вместо стека, вы выполняете обход в ширину. @Jeremiah представил обход, для которого я не знаю имени. Типичный «рекурсивный» порядок - это обычно обход в глубину.
Основным преимуществом типичной рекурсии является то, что длина стека не увеличивается так сильно, поэтому вы должны стремиться к глубине в целом ... если сложность не сокрушает вас:)
Я предлагаю начать с написания первого обхода дерева по глубине, как только это будет сделано, адаптация его к вашему алгоритму должна быть довольно простой.
РЕДАКТИРОВАТЬ: Поскольку у меня было некоторое время, я написал Обход дерева Python, это канонический пример:
class Node:
def __init__(self, el, children):
self.element = el
self.children = children
def __repr__(self):
return 'Node(' + str(self.element) + ', ' + str(self.children) + ')'
def depthFirstRec(node):
print node.element
for c in node.children: depthFirstRec(c)
def depthFirstIter(node):
stack = [([node,], 0), ]
while stack != []:
children, index = stack.pop()
if index >= len(children): continue
node = children[index]
print node.element
stack.append((children, index+1))
stack.append((node.children, 0))
Обратите внимание, что управление стеками немного усложняется из-за необходимости запоминать индекс дочернего элемента, который мы в данный момент посещали.
И адаптация алгоритма по порядку глубины:
def generateBrackets(c):
# stack is a list of pairs children/index
stack = [([(c,c,''),], 0), ]
while stack != []:
children, index = stack.pop()
if index >= len(children): continue # no more child to visit at this level
stack.append((children, index+1)) # register next child at this level
l, r, current = children[index]
if r == 0 and l == 0: print current
# create the list of children of this node
# (bypass if we are already unbalanced)
if l > r: continue
newChildren = []
if l != 0: newChildren.append((l-1, r, current + '<'))
if r != 0: newChildren.append((l, r-1, current + '>'))
stack.append((newChildren, 0))
Я только что понял, что хранение индекса немного "слишком" сложно, так как я никогда не захожу обратно. Таким образом, простое решение состоит в удалении элементов списка, которые мне больше не нужны, и обработке списка как очереди (на самом деле может быть достаточно стека)!
Это применимо с минимальным преобразованием.
def generateBrackets2(c):
# stack is a list of queues of children
stack = [[(c,c,''),], ]
while stack != []:
children = stack.pop()
if children == []: continue # no more child to visit at this level
stack.append(children[1:]) # register next child at this level
l, r, current = children[0]
if r == 0 and l == 0: print current
# create the list of children of this node
# (bypass if we are already unbalanced)
if l > r: continue
newChildren = []
if l != 0: newChildren.append((l-1, r, current + '<'))
if r != 0: newChildren.append((l, r-1, current + '>'))
stack.append(newChildren)