Бэктрекин без рекурсии на Python

Опубликовано 03 November 2016 в Python

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

Тем не менее, реализация бэктрекинга с рекурсией на Питоне элегантна, легко читаема и понятна. Отказываться от нее имеет смысл только для "тяжелых" задач.

def backtrack(self, solution):
    if solution in self.seen_solutions:
        return
    if self.reject(solution):
        return
    if self.accept(solution):
        self.output(solution)
    for child_solution in self.child_solutions(solution):
        self.backtrack(child_solution)

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

def backtrack(self, solution):
    solution_stack = [self.child_solutions(solution)]
    while True:
        current_generator = solution_stack[-1]
        solution = next(current_generator, None)
        while solution:
            if self.reject(solution):
                solution = next(current_generator, None)
                continue
            if self.accept(solution):
                self.output(solution)
            if not self.solution_is_complete(solution):
                solution_stack.append(self.child_solutions(solution))
                current_generator = solution_stack[-1]
            solution = next(current_generator, None)
        solution_stack = solution_stack[:-1]
        if not solution_stack:
            return
---
Возник вопрос? Мне всегда можно написать в Twitter: avkorablev