Проблемы вычисления выражения постфикса с более чем двумя операндами

0

Мне нужно создать калькулятор RPN (postfix notation), который делает простые операции (+, -, *,/), используя связанный список для поддержки стека. Я получил большинство из них, но я столкнулся с несколькими проблемами. Я могу вычислить любые два числа с одним операндом (например: 5 5 + = 10), но не может сделать ничего больше. Я провел некоторое исследование в Интернете и наблюдал за несколькими видеороликами YouTube, чтобы добраться туда, где я сейчас, но большинство используют ссылку на стек, чтобы сделать это. Я попытался объединить учебники по этому поводу, а также как создать собственный стек.

Я совершенно новичок в этом и довольно потерял, как вычислить большее выражение (например: 5 5 5 + + = 15), и мне также нужно проверить наличие ошибок, которые я выполнил, но те, которые я борется с "слишком много операторов" и "слишком много операндов". С слишком большим количеством операторов я предполагаю, что это имеет какое-то отношение к тому, что вы не можете выкинуть значение, потому что там нет никого, но что я могу получить (если он прав, все еще не совсем уверен, как реализовать Это). Любая помощь в любой из этих трех вещей или что-то еще, что вы можете увидеть здесь, будет очень оценена.

#include<iostream>
#include<string>
#include<sstream>
#include<iomanip>

using namespace std;

class SLLNode
{
    double data;
    SLLNode *top;
    SLLNode *ptr;
public:
    SLLNode()
    {
        top = NULL;
        ptr =  NULL;
    }
    void pushVal(double val)
    {
        SLLNode *next = new SLLNode;
        next -> data = val;
        next -> ptr = top;
        top = next;
    }
    double popVal()
    {
        SLLNode *next = new SLLNode;
        next = top;
        top = top -> ptr;
        next -> ptr = NULL;
        return next -> data;
        delete next;
    }
    void print()
    {
        SLLNode *next = new SLLNode;
        next = top;
        cout << "= " << next -> data << endl << ">>";
        next = next -> ptr;
        delete next;
    }
};

bool isOperator(const string& input)
{
    string ops[] = {"+", "-", "*", "/"};
    for(int i = 0; i < 4; i++)
    {
        if(input == ops[i])
        {
            return true;
        }
    }
    return false;
}

void performOp(const string& input, SLLNode& stack)
{
    double fVal, sVal;
    int result = 0;

    sVal = stack.popVal();
    fVal = stack.popVal();

    if(input == "+")
    {
        stack.pushVal(fVal + sVal);
    }
    else if(input == "-")
    {
        stack.pushVal(fVal - sVal);
    }
    else if(input == "*")
    {
        stack.pushVal(fVal*+ sVal);
    }
    else if(input == "/" && sVal != 0)
    {
        stack.pushVal(fVal / sVal);
    }

    if(input == "/" && sVal == 0)
    {
        cout << "Error: Division by zero" << endl;
        result = 1;
    }

    if(result == 0)
    {
        stack.print();
    }
}

int main()
{
    string input;
    SLLNode stack;

    cout << "::::::::::::::::RPN CALCULATOR:::::::::::::::::" << endl;
    cout << "::TYPE IN A POSTFIX EXPRESSION OR 'q' TO QUIT::" << endl;
    cout << ":::::::::::::::::::::::::::::::::::::::::::::::" << endl << endl;

    cout << ">>";
    while(true)
    {
        cin >> input;
        double num;

        if(istringstream(input) >> num)
        {
            stack.pushVal(num);
        }
        else if (isOperator(input))
        {
            performOp(input, stack);
        }
        else if (input == "q")
        {
            return 0;
        }
        else
        {
            cout << "Error: Invalid input" << endl;
        }
    }
}
Теги:
stack
postfix-notation
rpn

2 ответа

1
Лучший ответ

Сначала я бы рекомендовал вам использовать std::map<double> вместо того, чтобы переводить свой собственный связанный список, если только он не предназначен для обучения.

Основная проблема заключается в SLLNode::popVal() и SLLNode::print() где ситуация немного запуталась.

Вот что вам нужно изменить, чтобы исправить это:

double popVal()
{
    SLLNode *next = top -> ptr;
    double ret = top -> data;
    delete top;
    top = next;
    return ret;
}
void print()
{
    cout << "= " << top -> data << endl << ">>";
}

Есть много других вещей, которые вы могли бы улучшить в своем коде, но это должно ответить на ваш вопрос.

  • 0
    Фантастика, большое спасибо. Теперь все работает по большей части, просто нужно много чего почистить, но хотелось сначала выполнить основную функцию. Я действительно очень ценю это.
0

У вас есть два оператора: "*" и "+" в выражении для вычисления умножения. Я добавил и перестроил немного проверки ошибок,

int
performOp(const string& input, SLLNode& stack)
{
    double fVal, sVal;
    int result = 0;

    if( stack.size < 2 )
    {
        cout << "Error: too few operands" << end;
        stack.print();
        return 1;
    }

    sVal = stack.popVal();
    fVal = stack.popVal();

    if(input == "+")
    {
        stack.pushVal(fVal + sVal);
    }
    else if(input == "-")
    {
        stack.pushVal(fVal - sVal);
    }
    else if(input == "*")
    {
        stack.pushVal(fVal * sVal); //problem was here
    }
    else if(input == "/" )
    {
        if(sVal == 0)
        {
            cout << "Error: Division by zero" << endl;
            stack.print();
            return 1;
        }
        stack.pushVal(fVal / sVal);
    }

    return 0;
}

Определите узел списка, который содержит head/tail, и подсчет элементов в вашем стеке,

#include<iostream>
#include<string>
#include<sstream>
#include<iomanip>
using namespace std;

class SLLNode //single link list
{
public:
    SLLNode *next;
    double data;
    SLLNode()
    {
        next = NULL;
        data = 0;
    }
    void print()
    {
        SLLNode *node = NULL;
        cout << "= " << data << endl << ">>";
    }
};

Ваша реализация стека утешает память, выделяет ненужные узлы и не хватает нескольких полезных операций стека, которые помогут вам решить некоторые из ваших проблем. Вам нужен деструктор, который опустошает ваш список, если вы его забудете, и это поможет распечатать весь список. Так или иначе,

class SLList //single link list
{
    SLLNode *head;
    SLLNode *tail;
    int _count;
public:
    SLList()
    {
        head = NULL;
        tail = NULL;
        _count = 0;
    }
    ~SLList()
    {
        while( !empty() ) { pop(); }
    }
    int size() { return _count; }
    bool empty() { return (!head); return false; }
    void push(double val)
    {
        SLLNode *node = new SLLNode;
        node->data = val;
        node->next = head;
        ++_count;
        if(!tail) tail = node;
        head = node;
    }
    double pop()
    {
        SLLNode *node = NULL;
        if(!head) return 0;
        node = head;
        double val = node->data;
        head = node->next;
        --_count;
        if(!head) tail = NULL;
        delete node;
        return val;
    }
    double tip()
    {
        SLLNode *node = NULL;
        if(!head) return 0;
        node = head;
        double val = node->data;
        return val;
    }
    void print()
    {
        SLLNode *node = NULL;
        if(!head) return;
        for( node=head; node; node=node->next )
            node->print();
    }
};

Возможно, вам захочется добавить больше операторов, извлечь их,

bool isOperator(const string& input);
int performOp(const string& input, SLList& stack);
static string BINOPS[] = {"+", "-", "*", "/"};

bool
isOperator(const string& input)
{
    for(int i = 0; i < 4; i++) //should get size of BINOPS
    {
        if(input == BINOPS[i])
        {
            return true;
        }
    }
    return false;
}

Проверяйте свой уровень стека перед извлечением предметов из своего стека,

int
performOp(const string& input, SLList& stack)
{
    double fVal, sVal;
    int result = 0;

    if( stack.size() < 2 )
    {
        cout<<"Error: too few operands"<<endl;
        stack.print();
        return 1;
    }

    sVal = stack.pop();
    fVal = stack.pop();

    if(input == "+")
    {
        stack.push(fVal + sVal);
    }
    else if(input == "-")
    {
        stack.push(fVal - sVal);
    }
    else if(input == "*")
    {
        stack.push(fVal * sVal);
    }
    else if(input == "/" )
    {
        if(sVal == 0)
        {
            cout << "Error: Division by zero" << endl;
            stack.print();
            return 1;
        }
        stack.push(fVal / sVal);
    }

    return 0;
}

Вам нужно каким-то образом распечатать свой список. Четвертый язык используется ".", Поэтому здесь я добавил случай, чтобы распечатать список, используя ".",

int
main()
{
    string input;
    SLList stack;

    cout<<"::::::::::::::::RPN CALCULATOR:::::::::::::::::"<<endl;
    cout<<"::TYPE IN A POSTFIX EXPRESSION OR 'q' TO QUIT::"<<endl;
    cout<<":::::::::::::::::::::::::::::::::::::::::::::::"<<endl<<endl;

    double num;
    while(true)
    {
        cout << ">>";
        cin >> input;

        if(istringstream(input) >> num)
        {
            stack.push(num);
        }
        else if (isOperator(input))
        {
            performOp(input, stack);
        }
        else if (input == ".")
        {
            stack.print();
            double val = stack.tip();
            cout << "= " << val << endl << ">>";
        }
        else if (input == "q")
        {
            return 0;
        }
        else
        {
            cout << "Error: Invalid input" << endl;
        }
    }
}

Я также очистил еще пару ошибок.

  • 0
    *+ Не проблема вообще. + это просто унарный плюс здесь.
  • 0
    Спасибо! Ценю ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню