Как обойти дерево от "детей" к "родителям"
От: _FRED_ Черногория
Дата: 04.01.08 15:02
Оценка:
Не знаю, как надо решать такую вот задачу.

Есть дерево, которое представляет из себя <Expression>. <Expression> состоит из набора <Value> и <Expression> в произвольном порядке (но должно быть как минимум два дочерних элемента). <Value> — примитивное значение. <Expression> имеет признак {Operation}. Результатом применения {Operation} над <Expression> является, по сути, <Value>. Требуется вычислить <Value> для некоего <Expression>.

Пример
[+         // Начало <Expression> с {Operation} '+' 
  1,       // Вот это и есть <Value>
  [*
    2, 
    3, 
    [+
      4,
      5,
    ],
    6,
  ],
  7,
]


Требуется обойти дерево, выполнить операции и сосчитать результат. Начинается обход с корневого <Expression>.

У меня получился такой способ:
Имеется стек, элементом которого может быть либо <Value>, либо <Null>.
Идём по элементам:

То есть, применительно к примеру:
  1. Push <Null> // Корневое <Expression> с операцией '+'
  2. Push '1'
  3. Push <Null> // <Expression> с операцией '*'
  4. Push '2'
  5. Push '3'
  6. Push <Null> // <Expression> с операцией '+'
  7. Push '4'
  8. Push '5'
  9. Pop '5' // <Value> в последнем <Expression> закончились, вычисляем его…
  10. Pop '4'
  11. Pop <Null> // Заменяем маркер <Null> на значение <Expression>
  12. Push '9' (4 + 5)
  13. Push '6'
  14. Pop '6'
  15. Pop '9'
  16. Pop '3'
  17. Pop '4'
  18. Pop <Null>
  19. Push '324' (2 * 3 * 9 * 6)
  20. Push '7'
  21. Pop '7'
  22. Pop '324'
  23. Pop '1'
  24. Pop <Null>
  25. Push '332' (1 + 324 + 7)

В итоге в стеке только один элемент с результатом.

Насколько это нормальный "по науке" способ? Как надо по-правильному? Есть ли более "быстрые" или более "экономные" подходы?

У меня способ вызывает подозрение тем, что
  1. необходимо знать, что "<Expression> начался" и "<Expression> закончился". Обход сделан через Visitor и его интерфейс получается не классический:
    interface IVisitor
    {
      void VisitValue(Value value);
      void VisitExpression(Expression expression);
    }

    а специфический:
    interface IVisitor
    {
      void VisitValue(Value value);
    
      void VisitBeginExpression(Expression expression);
      void VisitEndExpression(Expression expression);
    }

    что, конечно, ни суть, ни механизм паттерна не меняет, но именно что "вызывает подозрение"
  2. приходится использовать специальные значения (<Null>) в стеке.

Можно ли (алгоритмически) избавиться от указанных недостатков?
Help will always be given at Hogwarts to those who ask for it.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.