Необходимо преобразовывать выражения в дизъюнктивную нормальную форму (если не ошибаюсь), т.е. на выходе не должно быть скобок, в выражениях есть операции + и *, у последней приоритет выше, ну как в жизни
![Smile :-)](./images/smilies/icon_smile.gif)
(a+b)*c -> a*c + b*c
Win32nipuh wrote:Коллеги, есть классическая задача, нужен алгоритм.
Необходимо преобразовывать выражения в дизъюнктивную нормальную форму (если не ошибаюсь), т.е. на выходе не должно быть скобок, в выражениях есть операции + и *, у последней приоритет выше, ну как в жизни
(a+b)*c -> a*c + b*c
Code: Select all
* +
+ c -> * *
a b a c b c
uuid wrote:Win32nipuh wrote:Коллеги, есть классическая задача, нужен алгоритм.
Необходимо преобразовывать выражения в дизъюнктивную нормальную форму (если не ошибаюсь), т.е. на выходе не должно быть скобок, в выражениях есть операции + и *, у последней приоритет выше, ну как в жизни
(a+b)*c -> a*c + b*c
Строишь дерево разбора
Потом опускаешь операции с большим приоритетом вниз.Code: Select all
* +
+ c -> * *
a b a c b c
Сворачиваешь дерево обратно в строку.
Для построения дерева нужен алгоритм Дейкстры.
Обойти полученное дерево слева направо?Win32nipuh wrote:Построить дерево не проблема, а вот алгоритм свертки?
Big Cheese wrote:Обойти полученное дерево слева направо?Win32nipuh wrote:Построить дерево не проблема, а вот алгоритм свертки?
Win32nipuh wrote:Big Cheese wrote:Обойти полученное дерево слева направо?Win32nipuh wrote:Построить дерево не проблема, а вот алгоритм свертки?
Обход дерева не проблема, как это сделать:
"Потом опускаешь операции с большим приоритетом вниз. " -?
Code: Select all
if leaf return;
else
{
if( priority of current node > piority of left node )
{
rebuild tree like this:
* +
+ c -> * *
a b a c b c
}
if( priority of current node > piority of right node )
{
same as above, node "c" and "+" поменяны местами.
}
if( both left and right nodes have smaller priority )
{
rebuild them both.
}
go down from left to right;
}
Code: Select all
print( left subtree );
print( operation in current node );
print( rihgt subtree );
uuid wrote:Win32nipuh wrote:Big Cheese wrote:Обойти полученное дерево слева направо?Win32nipuh wrote:Построить дерево не проблема, а вот алгоритм свертки?
Обход дерева не проблема, как это сделать:
"Потом опускаешь операции с большим приоритетом вниз. " -?
Приоритеты операций:
цифра/буква - 3, "+" - 1, "*" - 2;
Рекурсивно, все операции производятся над поддеревьями:Code: Select all
if leaf return;
else
{
if( priority of current node > piority of left node )
{
rebuild tree like this:
* +
+ c -> * *
a b a c b c
}
if( priority of current node > piority of right node )
{
same as above, node "c" and "+" поменяны местами.
}
if( both left and right nodes have smaller priority )
{
rebuild them both.
}
go down from left to right;
}
Свернуть дерево обратно в строку - простой обход дерева:Code: Select all
print( left subtree );
print( operation in current node );
print( rihgt subtree );
Даже скобки расставлять не надо, так как дерево "отсортировано" по приоритетам операций.
Win32nipuh wrote:Идея понятна, уточнение:
при перестройке начинаем обход с корня, т.е. приблизительно так:
Regresion(pRootNode);
void Regresion(CNode* pRootNode)
{
//processing as above described
Regresion(pRootNode->GetLeftNode());
Regresion(pRootNode->GetRightNode());
}
Code: Select all
printf( left_subtree );
printf( left_subtree );
printf( operation );
uuid wrote:Win32nipuh wrote:Идея понятна, уточнение:
при перестройке начинаем обход с корня, т.е. приблизительно так:
Regresion(pRootNode);
void Regresion(CNode* pRootNode)
{
//processing as above described
Regresion(pRootNode->GetLeftNode());
Regresion(pRootNode->GetRightNode());
}
Типа того. Все равно придется добиться чтобы работало.
В принципе используя такое дерево можно что угодно делать - брать производные в аналитическом виде (лучше конечно увеличить количество операций, можно ввести функции), вычислять выражения, упрощать выражения.
Разные обходы дают разные виды записей. НапримерCode: Select all
printf( left_subtree );
printf( left_subtree );
printf( operation );
дает обратную польскую (или венгерскую, как ее там) запись. В ней вообще скобок не бывает и вычисляется она с помощью только стека.
Win32nipuh wrote:Спасибо, uuid, Ваша предыдущая посдказка помогла, правда, сначала сбило с толку то, что перестраивать оба поддерева нужно, я так и начал честно реализовывать, три варианта. Но, оказадось, что достаточно двух первых веток, третья укладывается в первые.Т.е. когда * в вершине, а в двух чилдах +.
Отлично строится ДНФ, то, что надо.