Алгоритм маневровой станции на С++

Мне нужна функция, которая принимает инфиксную строку (например, "3 + 4 * 9") и преобразует ее в постфиксную (например, "4 9 * 3 +").

У меня это работает, пока вы не добавите скобки в скобки. Я работаю над этим весь день и не могу понять, что я делаю неправильно - может быть, кто-нибудь со свежим умом увидит это? Я чувствую, что я действительно близко!

Спасибо! Вот код:

    string ExpressionManager::infixToPostfix(string infixExpression)
    {
cout << "itop Testing : " << infixExpression << endl;
string posnums = "0123456789";
string posops = "+-*/%(){}[]";
string onlyops = "+-/%*";
string space = " ";
string openbra = "([{";
string closebra = ")]}";
stack <string> nums;
stack <string> ops;
string output = "";

//check to make sure expression is valid

if (!(isBalanced(infixExpression)))
{
    cout << "Infix Expression isn't balanced!" << endl;
    return "invalid";
}


for (int i=0; i<infixExpression.size(); i++)
{
    if ((posnums.find(infixExpression[i])!=string::npos) || (posops.find(infixExpression[i])!=string::npos) || (space.find(infixExpression[i])!=string::npos))
    {}

    else
    {
        cout << "Invalid character " << infixExpression[i] << " found." << endl;
        return "invalid";
    }
}


int numcount = 0;
int opcount = 0;
//Numbers vs. Operators
for (int i = 0; i < infixExpression.size(); i++)
{
    if (posnums.find(infixExpression[i]) != -1)
    {

        while(infixExpression[i] != ' ')
        {
            if (i == (infixExpression.size()-1))
                break;
            i++;
        }
        numcount++;
    }

    if (onlyops.find(infixExpression[i]) != -1)
    {
        opcount++;
    }
}


if (opcount == (numcount - 1))
{
}
else
{
    cout << "Bad operators to numbers ratio!" << endl;
    return "invalid";
}

//Get rid of proceeding whitespaces.
int safety = 0;
int net = infixExpression.size();

while (infixExpression[0] == ' ')
{
    infixExpression.erase(0,1);
    safety++;

    if (safety>=net)
        break;
}

//cout << "At this point, it is " << postfixExpression << endl;

//the fun part! Set up stacks

for (int i =0; i< infixExpression.size(); i++)
{
    cout << "It gets hung up on character " << infixExpression[i] << endl;
    if(openbra.find(infixExpression[i]) != -1)
    {

        string word = "";
        word += infixExpression[i];
        ops.push(word);

        cout << "Pushing onto stack: " << word << endl;
    }
    else if(closebra.find(infixExpression[i]) != -1)
    {
            cout << "contents of remaining ops stack: "<< endl;
            stack <string> temp;
            temp = ops;
                for (int j = 0; j < temp.size(); j++)
                {
                    cout << "\t" << temp.top() << endl;
                    temp.pop();
                }

        while (openbra.find(ops.top()) == -1)
        {


            output += " " + ops.top();
            cout << "Pushing from stack: " << ops.top() << endl;
            ops.pop();
        }

        cout << "Pushing from stack: " << ops.top() << endl;
        ops.pop();

    }

    else if (posnums.find(infixExpression[i]) != -1)
    {

        string word = "";
        while (infixExpression[i] != ' ')
        {
            word += infixExpression[i];
            i++;
            if (i== infixExpression.size())
                break;
        }
        output += " " + word;

    }

    else if (onlyops.find(infixExpression[i]) != -1)
    {

        if (ops.size() == 0)
        {
            string word = "";
        word += infixExpression[i];
        ops.push(word);
        }
        else
        {
        int o1p = 0;
        int o2p = 0;

        if ((infixExpression[i] == '+') || (infixExpression[i] == '-'))
            o1p = 0;
        else
            o1p = 1;

        if ((ops.top() == "+") || (ops.top() == "-"))
            o2p = 0;
        else
            o2p = 1;

        while ((ops.size() > 0) && (o1p <= o2p))
        {
            output += " " + ops.top();
            cout << "(odd) Pushing from stack: " << ops.top() << endl;

        if ((ops.top() == "+") || (ops.top() == "-"))
            o2p = 0;
        else
            o2p = 1;

        if (ops.size() > 0)
        {
            ops.pop();
        }
        else
        {
            break;
        }
        }

        string word = "";
        word += infixExpression[i];
        ops.push(word);
        }
    }

}

while (output[0] == ' ')
{
    output.erase(0,1);
}

return output;
    }

person user1311736    schedule 12.10.2012    source источник
comment
Лишь бы начиналось как рекурсивно-спусковое, а не маневровое.. :)   -  person    schedule 12.10.2012
comment
Вау. Shift-Reduce-parser воспоминание. Я думал, что оставил такие вопросы еще в колледже много лун назад.   -  person WhozCraig    schedule 12.10.2012
comment
Правильный вывод должен быть 3 4 9 * +. Когда вы анализируете его позже, вы перебираете все элементы, пока не найдете первый оператор. Затем вы заменяете этот оператор и два операнда впереди результатом этой операции, а затем ищете следующий оператор.   -  person Atle    schedule 24.10.2013


Ответы (3)


Я предлагаю вам перейти прямо на соответствующие страницы вики, которые описывают

  1. Алгоритм маневровой станции
  2. Обратная польская нотация

Я реализовал алгоритм Shunting Yard как на Java, так и на C++ и нашел страницы Wiki превосходными и отличным источником помощи. Они достаточно подробны, чтобы вы могли реализовать алгоритм шаг за шагом на любом языке программирования, который вы предпочитаете.

Еще одно предложение: ознакомьтесь с практическим использованием стеков и очередей, поскольку они повсеместно используются в этих алгоритмах.

См. эту публикацию в блоге для некоторых C++ и Java-реализации указанного алгоритма Shunting Yard.

Он также содержит дополнительный раздел (в разработке), если вы хотите включить другие математические операторы (sin, cos, log и т. д.), а также более сложные выражения и подвыражения.

person AndyUK    schedule 14.04.2013

Я лично думаю, что вам нужно усерднее изучать алгоритм Shunting-yard.

Потому что вы сказали, что вывод похож на "4 9 * 3 +", но то, что я читал об алгоритме и работе стека, должно быть (например, "9 4 * 3 +")

Важная проблема заключается в том, что после классификации числа и операторов выталкивать все из стека операторов и помещать в стек чисел в соответствии с заданными условиями, для которых оператор должен быть выскочен.

person Raju yourPepe    schedule 12.10.2012

Вот (последняя версия) решение. На каком-то шаге он использует алгоритм маневровой станции Дейкстры (в конце функции-члена traverse() член output_ содержит обратную полированную форму записи выражения input_, если мы обходим его правильно).

person Tomilov Anatoliy    schedule 13.10.2013