Моя стратегия состоит в том, чтобы построить дерево разбора, а затем обойти его по глубине, чтобы создать префиксную нотацию.
Вы можете построить дерево разбора из ORF с помощью очереди. Когда вы встретите каждого оператора (или термин), сделайте его дочерним по отношению к оператору во главе очереди. Когда у узла в начале очереди достаточно дочерних элементов, вытолкните его из очереди.
В вашем примере ... Начните с +
и поместите его в очередь (особый случай для начального элемента).
Следующий процесс /
. Поскольку +
в начале очереди не имеет дочерних элементов (но нуждается в двух), вы присоединяете /
к +
в качестве первого дочернего элемента и помещаете /
в очередь. Так что теперь очередь выглядит так:
+/
... и дерево выглядит как
+
/ .
. .
... где "." элемент, ожидающий заполнения.
Далее следует sqrt
. Поскольку +
находится в начале очереди и еще не имеет двух дочерних элементов, присоедините sqrt
к +
и вставьте sqrt
в очередь. Так что теперь очередь выглядит так:
+/sqrt
... и дерево выглядит как
+
/ sqrt
. . .
Далее идет вторая +
. Глава очереди - первый +
, но теперь у него уже есть все его дети. Так что выкинь это из очереди. Следующим элементом очереди является /
, и у него еще нет дочерних элементов, поэтому этот +
становится его дочерним элементом и переходит в конец очереди. Очередь теперь гласит:
/sqrt+
... а дерево сейчас:
+
/ sqrt
+ . .
. .
Затем третий +
становится вторым дочерним элементом /
и помещается в очередь. Так что очередь будет:
/sqrt++
... и дерево будет (извините, моя ASCII-графика слаба):
+
/ sqrt
+ + .
. . . .
Теперь /
удовлетворен, поэтому, когда вы нажимаете e
, вы вытаскиваете /
из очереди. Теперь sqrt
является началом очереди, поэтому e
привязывается к этому. Очередь сейчас:
sqrt++
... а дерево есть:
+
/ sqrt
+ + e
. . . .
Следующие четыре итерации, очевидно, присваивают a, b, c, d оставшимся листьям, давая вам ваше дерево разбора.
Кстати,
std::dequeue
- это идеальная структура данных для очереди.