Мне нужно создать калькулятор RPN (постфиксной нотации), который выполняет простые операции (+, -, *, /), используя при этом связанный список для поддержки стека. Я выполнил большинство из них, но столкнулся с несколькими проблемами. Я могу вычислить любые два числа с одним операндом (например: 5 5 + = 10), но не могу сделать что-то большее. Я провел некоторое онлайн-исследование и посмотрел несколько видео на YouTube, чтобы узнать, где я сейчас нахожусь, но большинство используют для этого ссылки на стек. Я попытался объединить учебники по этому вопросу вместе с тем, как сделать свой собственный стек.
Я новичок в этом, и я довольно растерялся в том, как рассчитать большее выражение (например: 5 5 5 + + = 15), и мне также нужно проверить ошибки, некоторые из которых я выполнил, но те, которые я борются с «слишком много операторов» и «слишком много операндов». Слишком много операторов, я полагаю, что это связано с невозможностью вытолкнуть значение, потому что его там нет, но это все, что я могу получить (если это правильно, все еще не совсем уверен, как реализовать Это). Любая помощь с любым из этих 3 вещей, или что-либо еще, что вы можете увидеть здесь, будет принята с благодарностью.
#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;
}
}
}
Сначала я бы порекомендовал вам использовать 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 << ">>";
}
Есть много других вещей, которые вы могли бы улучшить в своем коде, но это должно ответить на ваш вопрос.
У вас есть два оператора, ‘*’ и ‘+’ в вашем выражении для вычисления умножения. я добавил & переставил немного проверки ошибок,
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;
}
Определите узел списка, который содержит голову / хвост и считает элементы в вашем стеке,
#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;
}
}
}
Я также убрал пару других ошибок.