Преобразование инфикса в постфикс С++

Я пытаюсь преобразовать инфикс в постфикс, а затем оценить постфиксное выражение, чтобы получить окончательный ответ. Однако у меня возникла серьезная проблема, потому что по какой-то причине преобразование вообще не работает. Например, когда я ввожу первое инфиксное выражение: 24 + 33 * ( 7 - 5 ) + 8 / 3, оно выводит 24 33 7 5 45404243 8 34743, что, очевидно, очень неправильно. Я не совсем уверен, где проблема, хотя. Ниже я включил весь необходимый код. Мне также пришлось создать свой собственный класс стека, поэтому я тоже включу его, если это поможет. Любые советы будут очень признательны!

#include "stacks.h"
#include <iostream>
#include <string>


using namespace std;

bool IsOperand(char C)
{
    if(C >= '0' && C <= '9') return true;
    return false;
}

bool IsOperator(char C)
{
    if(C == '+' || C == '-' || C == '*' || C == '/')
        return true;

    return false;
}
int GetOperatorWeight(char op)
{
    int weight = -1;
    switch(op)
    {
        case '+':
        case '-':
            weight = 1;
        case '*':
        case '/':
            weight = 2;
    }
    return weight;
}

int HasHigherPrecedence(char op1, char op2)
{
    int op1Weight = GetOperatorWeight(op1);
    int op2Weight = GetOperatorWeight(op2);

    return op1Weight > op2Weight ?  true: false;
}

int PerformOperation(char operation, int operand1, int operand2)
{
    if(operation == '+') return operand1 +operand2;
    else if(operation == '-') return operand1 - operand2;
    else if(operation == '*') return operand1 * operand2;
    else if(operation == '/') return operand1 / operand2;

    else cout<<"Unexpected Error \n";
    return -1; 
}

bool IsNumericDigit(char C)
{
    if(C >= '0' && C <= '9') return true;
    return false;
}

int evalPost(string item)
{
    stacks S;

    for(int i = 0;i< item.length();i++) {


        if(item[i] == ' ' || item[i] == ',') continue;

        else if(IsOperator(item[i])) {

            int operand2 = stoi(S.stackTop()); S.pop();
            int operand1 = stoi(S.stackTop()); S.pop();

            int result = PerformOperation(item[i], operand1, operand2);

            S.push(to_string(result));
        }
        else if(IsNumericDigit(item[i]))
        {
            int operand = 0;
            while(i<item.length() && IsNumericDigit(item[i]))
            {
                operand = (operand*10) + (item[i] - '0');
                i++;
            }

            i--;

            S.push(to_string(operand));
        }
    }
    return stoi(S.stackTop());
}



string infToPost(string item)
{
    stacks S;
    string postfix = "";
    for(int i = 0;i< item.length();i++) {
        cout<<postfix<<endl;
        if(item[i] == ' ')
            postfix +=item[i];

        else if(IsOperator(item[i]))
        {

            while(!S.empty() && S.stackTop() != "(" && HasHigherPrecedence(*(S.stackTop().c_str()),item[i]))
            {
                postfix+= S.stackTop();
                S.pop();
            }
            S.push(to_string(item[i]));
            //S.pop();
        }

        else if(IsOperand(item[i]))
        {
            postfix +=item[i];
        }

        else if (item[i] == '(')
        {
            S.push(to_string(item[i]));
        }

        else if(item[i] == ')')
        {
            while(!S.empty() && S.stackTop() !=  "(") {
                postfix += S.stackTop();
                S.pop();
            }
            S.pop();
        }
    }


    while(!S.empty()) {
        postfix += S.stackTop();
        S.pop();
    }

    return postfix;
}

int main()
{
    string selection="";
    string infix;
    string postfix;
    string eval;
    cout<<"***********************************************************"<<endl;
    cout<<"1. Read an expression in infix notation."<<endl;
    cout<<"2. Convert infix to postfix."<<endl;
    cout<<"3. Evaluate the expression using postfix notation."<<endl;
    cout<<"4. Exit"<<endl;
    cout<<"***********************************************************"<<endl;
    cout<<"Select: ";
    getline(cin, selection);
//    cin>>selection;
//    cin.ignore();
    while (selection>"4" || selection<"1")
    {
        cout<< "Please enter a different choice (1-4): ";
        getline(cin, selection);
    }
    while(selection!="4")
    {

        if (selection=="1")
        {
            cout<<"Enter an infix expression: ";
            getline(cin,infix);
            cout<<"\n";
        }

        if(selection=="2")
        {
            cout<<"Infix expression: "<<infix<<endl;
            postfix = infToPost(infix);
            cout<<"Postfix expression: "<<postfix<<endl;
            cout<<"\n";
        }

        if(selection=="3")
        {
            cout<<"Infix expression: "<<infix<<endl;
            eval = evalPost(postfix);
            cout<<"Evaluation of this expression: "<<endl;
            cout<<"\n";
        }

        selection = "";
        cout<<"***********************************************************"<<endl;
        cout<<"1. Read an expression in infix notation."<<endl;
        cout<<"2. Convert infix to postfix."<<endl;
        cout<<"3. Evaluate the expression using postfix notation."<<endl;
        cout<<"4. Exit"<<endl;
        cout<<"***********************************************************"<<endl;
        cout<<"Select: ";
        getline(cin,selection);
        //cin.ignore();
        while (selection>"4" || selection<"1")
        {
            cout<< "Please enter a different choice (1-4): ";
            getline(cin, selection);
        }
    }
    cout<<"Thank you for using my program."<<endl;
    return 0;

}

ЗАГОЛОВОК КЛАССА СТЕКА

#ifndef __Programming_Assingment
#include "stacks.h"
#include <iostream>
#include <string>

using namespace std;

//Contstructor
stacks::stacks()
{
    top = -1;
}

//push the item onto the stack
void stacks::push(string item)
{
    sstack.push_back(item);
    top++;
}

//check if the stack is empty
bool stacks::empty()
{
    if (top==-1)
        return true;
    else
        return false;
}

//delete the last item on the stack
void stacks::pop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch(int err){
        cout<<"stack is empty."<<endl;
        cout<<"Cannot pop an item."<<endl;
        return;
    }
    sstack.pop_back();
    top--;
}

//get the top of the stack
string stacks::stackTop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch (int err) {
        cout<< "stack is empty."<<endl;
        return 0;
    }
    return (sstack[top]);
}
_stacks__ #define __Programming_Assingment
#include "stacks.h"
#include <iostream>
#include <string>

using namespace std;

//Contstructor
stacks::stacks()
{
    top = -1;
}

//push the item onto the stack
void stacks::push(string item)
{
    sstack.push_back(item);
    top++;
}

//check if the stack is empty
bool stacks::empty()
{
    if (top==-1)
        return true;
    else
        return false;
}

//delete the last item on the stack
void stacks::pop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch(int err){
        cout<<"stack is empty."<<endl;
        cout<<"Cannot pop an item."<<endl;
        return;
    }
    sstack.pop_back();
    top--;
}

//get the top of the stack
string stacks::stackTop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch (int err) {
        cout<< "stack is empty."<<endl;
        return 0;
    }
    return (sstack[top]);
}
_stacks__ #include <string> #include <vector> using namespace std; //define the stacks class class stacks { public: //constructor stacks(); //push function void push(string item); //pop function void pop(); //function to get top of stack string stackTop(); //check if stack is empty bool empty(); private: //create vector and integer int top; vector<string> sstack; }; #endif /* defined(__Programming_Assingment
#include "stacks.h"
#include <iostream>
#include <string>

using namespace std;

//Contstructor
stacks::stacks()
{
    top = -1;
}

//push the item onto the stack
void stacks::push(string item)
{
    sstack.push_back(item);
    top++;
}

//check if the stack is empty
bool stacks::empty()
{
    if (top==-1)
        return true;
    else
        return false;
}

//delete the last item on the stack
void stacks::pop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch(int err){
        cout<<"stack is empty."<<endl;
        cout<<"Cannot pop an item."<<endl;
        return;
    }
    sstack.pop_back();
    top--;
}

//get the top of the stack
string stacks::stackTop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch (int err) {
        cout<< "stack is empty."<<endl;
        return 0;
    }
    return (sstack[top]);
}
_stacks__) */

CPP-ФАЙЛ КЛАССА СТЕКА

#include "stacks.h"
#include <iostream>
#include <string>

using namespace std;

//Contstructor
stacks::stacks()
{
    top = -1;
}

//push the item onto the stack
void stacks::push(string item)
{
    sstack.push_back(item);
    top++;
}

//check if the stack is empty
bool stacks::empty()
{
    if (top==-1)
        return true;
    else
        return false;
}

//delete the last item on the stack
void stacks::pop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch(int err){
        cout<<"stack is empty."<<endl;
        cout<<"Cannot pop an item."<<endl;
        return;
    }
    sstack.pop_back();
    top--;
}

//get the top of the stack
string stacks::stackTop()
{
    try{
        if (sstack.size()==0) throw 0;
    } catch (int err) {
        cout<< "stack is empty."<<endl;
        return 0;
    }
    return (sstack[top]);
}

person whoisthis88    schedule 13.04.2015    source источник
comment
Я отлаживал как сумасшедший (или, по крайней мере, пытался). А мне не очень повезло. Кажется, правильно хранить числа в постфиксной переменной, пока не придет время добавить оператор в конец. Когда это происходит, это немного сходит с ума, и я не знаю, почему. По какой-то причине я думаю, что стек никогда ничего не получает, и я не знаю, почему.   -  person whoisthis88    schedule 13.04.2015
comment
Хорошо, я только что раскомментировал один из S.pop(), который у меня был, и это резко изменило мой вывод. Теперь я получаю 24 33 7 5 40 8 3, когда ввожу то, о чем упоминал ранее. Но я до сих пор не знаю, что происходит с операторами и почему они не работают со стеком.   -  person whoisthis88    schedule 13.04.2015
comment
Мне также пришлось создать свой собственный класс стека, поэтому я его тоже включу... - было бы гораздо лучше написать свой код для использования std::stack, а затем, как только он заработает, посмотреть, работает ли он работает с вашим собственным стеком... если нет, по крайней мере, вы знаете, где отлаживать.   -  person Tony Delroy    schedule 13.04.2015
comment
Я попытался использовать обычный класс стека, но когда я это сделал, он даже не вывел то, что у меня уже было, что довольно близко. Я думаю, что то, как я это изложил, подходит для моего класса стека вместо стандартного.   -  person whoisthis88    schedule 13.04.2015
comment
Всего несколько замечаний: во-первых, извлеките минимальный пример. Все это взаимодействие с пользователем (ввод/вывод) и разделение на несколько файлов не должны быть необходимы для демонстрации проблемы, если назвать несколько вещей. Тогда каков точный результат вашей программы? Что ты ожидал? Они должны быть предоставлены в любое время, когда вы публикуете вопросы здесь! Затем проверьте свой код, где вы обнаружите ошибки, а затем продолжайте игнорировать их. Ваш класс стека делает ужасную работу.   -  person Ulrich Eckhardt    schedule 13.04.2015
comment
Я думаю, что теперь он выводит правильный постфикс. Но оценка постфикса не работает. Я получаю сообщение об ошибке: libc++abi.dylib: завершение с необработанным исключением типа std::invalid_argument: stoi: нет преобразования Я ожидаю, что он выведет 92. Это когда я вставил инфикс 24 + 33 * ( 7 - 5 ) + 8/3   -  person whoisthis88    schedule 13.04.2015


Ответы (1)


Когда вы помещаете оператор в свой стек, используя эту строку:

S.push(to_string(item[i]));

to_string берет символ и обрабатывает его как целое число. Это приводит к таким строкам, как «43» для «+» и «45» для «-».

Вместо этого вы хотите создать строку, содержащую только этот символ. Один из способов сделать это — использовать конструктор строк, который принимает значение count и char. Используйте счет 1.

S.push(std::string(1, item[i]));

Изменить: вот функция infoToPost с изменениями. Не изменяйте никаких других вызовов to_string в других методах, так как они все еще необходимы (поскольку вы хотите преобразовать целочисленные значения в строки).

string infToPost(string item)
{
    stacks S;
    string postfix = "";
    for (int i = 0; i< item.length(); i++) {
        cout << postfix << endl;
        if (item[i] == ' ')
            postfix += item[i];

        else if (IsOperator(item[i]))
        {

            while (!S.empty() && S.stackTop() != "(" && HasHigherPrecedence(*(S.stackTop().c_str()), item[i]))
            {
                postfix += S.stackTop();
            S.pop();
            }
            S.push(string(1, item[i]));
            //S.pop();
        }

        else if (IsOperand(item[i]))
        {
            postfix += item[i];
        }

        else if (item[i] == '(')
        {
            S.push(string(1, item[i]));
        }

        else if (item[i] == ')')
        {
            while (!S.empty() && S.stackTop() != "(") {
                postfix += S.stackTop();
                S.pop();
            }
            S.pop();
        }
    }


    while (!S.empty()) {
        postfix += S.stackTop();
        S.pop();
    }

    return postfix;
}
person The Dark    schedule 13.04.2015
comment
Хорошо, так что это очень помогло! Он удалил 40-е, которые появлялись. Но операторов на выходе по-прежнему нет, и меня это очень смущает. Итак, теперь мой вывод равен 24 33 7 5 8 3. - person whoisthis88; 13.04.2015
comment
Хм, у меня сработало нормально (обратите внимание, что я использовал std::stack, так что это все еще может быть вашей проблемой). Вы также изменили обработчик '('? - person The Dark; 13.04.2015
comment
Я изменил обработчик '('. Позвольте мне быстро попробовать его с обычным классом стека. Если он работает, то, очевидно, проблема в моем классе. - person whoisthis88; 13.04.2015
comment
Итак, когда я использовал обычный класс, я получил это: 24 33 7 5 - 8 3/++* Это правильно? Из того, что у меня есть, это неправильно. Я также получаю этот ответ, когда использую свой класс стека и удаляю один из операторов pop (как-то странно) - person whoisthis88; 13.04.2015
comment
Это неправильно, но близко. Вы должны пройти через отладчик, если можете, и обратить пристальное внимание на функцию GetOperatorWeight. На данный момент у вас есть то, что вы получили бы, если бы все операторы имели одинаковый приоритет. - person The Dark; 13.04.2015
comment
Я так близок к этому, я изменил свой приоритет, и теперь мой вывод равен 24 33 7 5 - * 8 3/++ Так что слишком много плюсов. Тем не менее, он все еще не оценивает это правильно - person whoisthis88; 13.04.2015
comment
И ваш результат в порядке, вы просто присваиваете его результату string, а не результату int. Это дает вам противоположный эффект, который у вас был раньше, когда теперь он обрабатывает int как char. Вы также нигде не печатаете результат. - person The Dark; 13.04.2015
comment
Я возвращаю результат переменной postfix позже в основной функции. Я печатаю оттуда. Итак, как бы вы порекомендовали мне справиться с функцией оценки? Должен ли я преобразовать все в int? - person whoisthis88; 13.04.2015
comment
Использование: int val = evalPost(postfix); cout << "Evaluation of this expression: " << val << endl; (в две строки) - person The Dark; 13.04.2015
comment
Обратите внимание, что вы выполняете только целочисленную арифметику, поэтому ожидаемый результат для примера выражения равен 92. - person The Dark; 13.04.2015
comment
Не могу поверить, что не заметил, как забыл его распечатать. Но даже в этом случае я получаю эту ошибку: libc++abi.dylib: завершение с необработанным исключением типа std::invalid_argument: stoi: нет преобразования Когда я пытаюсь оценить постфикс. Это происходит здесь: int operand2 = stoi(S.stackTop()); - person whoisthis88; 13.04.2015
comment
Это может быть связано с вашей реализацией стека - вы когда-нибудь выясняли, почему вам пришлось удалить один из операторов pop? Вы всегда можете опубликовать свой код стека в качестве редактирования своего вопроса (внизу не удаляйте текущий код). - person The Dark; 13.04.2015
comment
Я предполагаю, что это означает, что преобразование stoi не нужно, но если я удалю, возникнет ошибка, говорящая о том, что он не может автоматически преобразовать из строки в int. - person whoisthis88; 13.04.2015
comment
Позвольте мне добавить это очень быстро - person whoisthis88; 13.04.2015
comment
Я добавил его, но так и не понял, почему он ведет себя странно. - person whoisthis88; 13.04.2015
comment
Я снова начал с вашего исходного кода, изменил пару вызовов to_string (только операторские), исправил break в GetOperatorWeight и изменил вывод на тот, который я разместил выше, и получил результат 92. Если вы не получив это, вы, должно быть, изменили что-то еще. - person The Dark; 13.04.2015
comment
Я не знаю, что я меняю. Я взял то, что у меня было изначально, и изменил все to_string, которые у меня были, в предложенный вами формат. Я также изменил функцию GetOperatorWeight, чтобы она работала, и теперь у меня тоже есть правильный вывод. Но я все еще получаю сообщение об ошибке. - person whoisthis88; 13.04.2015
comment
Не хотелось бы спрашивать, но не могли бы вы показать мне фрагмент того, что вы изменили по сравнению с моим исходным кодом? Потому что у меня проблемы с int operand2 = stoi(S.stackTop()); - person whoisthis88; 13.04.2015
comment
Вот в чем разница - мое изменение: изменил пару вызовов to_string (только операторские) ваше изменение: изменил все to_string, которые у меня были, в предложенный вами формат. Не изменяйте вызовы операнда и результата to_string, так как на самом деле вы хотите преобразовать эти целые числа в строки. - person The Dark; 13.04.2015
comment
Это исправило это! Большое спасибо за вашу помощь сегодня вечером! Вы оказали удивительную помощь! - person whoisthis88; 13.04.2015