Какой код python генерирует все возможные группировки (деревья) для двоичных операторов

Как объясняется в нескольких Так вопросов, и более абстрактно на mathworld, последовательность каталонских чисел соответствует числу парентетических группировок, которые могут быть сгенерированы для любого заданного числа операторов. Но я не нашел алгоритма для генерации всех этих группировок.

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

веб-поиск показал одна реализация в C# но я думаю, что мне потребуется некоторое время, чтобы понять, поскольку я не знаю синтаксиса C#.

Итак, какой код python генерирует все возможные группировки скобок вокруг операторы (которые, таким образом, могут использоваться с фактическим выражением для генерации всех возможностей)? Вывод будет выглядеть следующим образом для 2, 3, и лучше бы был код, который делал что-то вроде следующего:

AllBinaryTrees("2+3/4")

выход:

  1. 2+(3/4)
  2. (2+3)/4

2 ответов


как о

def allbinarytrees(s):
    if len(s) == 1:
        yield s
    else:
        for i in range(1, len(s), 2):
            for l in allbinarytrees(s[:i]):
                for r in allbinarytrees(s[i+1:]):
                    yield '({}{}{})'.format(l, s[i], r)

пример использования:

for t in allbinarytrees('1+2-3*4/5'):
    print(t)

выход:

(1+(2-(3*(4/5))))
(1+(2-((3*4)/5)))
(1+((2-3)*(4/5)))
(1+((2-(3*4))/5))
(1+(((2-3)*4)/5))
((1+2)-(3*(4/5)))
((1+2)-((3*4)/5))
((1+(2-3))*(4/5))
(((1+2)-3)*(4/5))
((1+(2-(3*4)))/5)
((1+((2-3)*4))/5)
(((1+2)-(3*4))/5)
(((1+(2-3))*4)/5)
((((1+2)-3)*4)/5)

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

def allbinarytrees(s):
    if s.isdigit():
        yield s
    else:
        i = 0
        while i < len(s)-1:
            while i < len(s) and s[i].isdigit():
                i += 1
            if i < len(s) - 1:
                for left in allbinarytrees(s[:i]):
                    for right in allbinarytrees(s[i+1:]):
                        yield '({}{}{})'.format(left, s[i], right)
            i += 1

пример использования:

j=0
for t in allbinarytrees('11+22*3/4456'):
    j += 1
    print j, (t[1:-1])

выход:

1 11+(22*(3/4456))
2 11+((22*3)/4456)
3 (11+22)*(3/4456)
4 (11+(22*3))/4456
5 ((11+22)*3)/4456