I am writing code for postfix expression evaluation with +,-,*,/ and ^ operators. It should take input from the command line as a string which is a postix notation of an expression (whitespace is used as a delimiter). The program should print the result of the expression on the console.
The code I have written works fine for all test cases with integer values. E.g. it works for input: 2 2 2 * +
I have tried to change the stack input value to float rather than an int but it still doesn't work.
using namespace std;
struct node
{
float data ;
node *next ;
};
class stack
{
private :
node *head;
public :
stack()
{
head = NULL;
}
void push(float a)
{
node * temp = new node();
temp ->data = a ;
temp -> next = head ;
head = temp ;
}
int pop()
{
node *temp = head ;
head = temp->next ;
int a = temp->data ;
delete temp;
return a;
}
int see_top()
{
if(is_empty())
return 0 ;
node * temp = head ;
return (temp->data);
}
int is_empty()
{
if(head == NULL)
return 1;
else
return 0 ;
}
};
int is_digit(char a)
{
if(a >= '0' && a<= '9')
return 1;
else
return 0;
}
int is_operand(char a)
{
switch(a)
{
case '+' :
case '-' :
case '*' :
case '/' :
case '^' : return 1;
default : return 0;
}
}
float operation(float a , float b , char sym)
{
float ans ;
switch(sym)
{
case '+' : ans = a + b ;
break;
case '-' : ans = a - b ;
break ;
case '*' : ans = a*b ;
break ;
case '/' : ans = a/b ;
break ;
case '^' : ans = pow(a,b) ;
break ;
default : break ;
}
return ans ;
}
int main()
{
char exp[100];
stack s ;
float num=0 , num1=0 , num2=0 ;
int l , i ;
cout << "Enter the posfix expression : ";
cin.getline(exp,100);
l=strlen(exp);
for(i=0;i<l;i++)
{
if(is_digit(exp[i]))
{
num = 0;
while(exp[i]!=' ')
{
int a = exp[i++]- '0';
num = 10*num + a ;
}
s.push(num);
}
else if(is_operand(exp[i]))
{
num2 = s.see_top();
s.pop();
num1 = s.see_top();
s.pop();
num = operation(num1 , num2 , exp[i]);
s.push(num);
}
else
continue;
}
num = s.see_top();
s.pop();
cout << "Answer : " << num ;
return 0 ;
}
When I try to input an expression with some float values, it doesn't return the correct value. E.g. ideally for an expression 0.5 0.5 *, it should return 0.25 but it rather returns 225. For expression 0.1 0.1 + it returns -36.
The code looks very good! .
You are almost there. There are three problems in the code:
pop() casts everything to int
see_top() casts everything to int
The decimal point parsing does not work.
Here is an updated pop() and see_top(). Notice that they now return float.
float pop()
{
node *temp = head;
head = temp->next;
float a = temp->data;
delete temp;
return a;
}
float see_top()
{
if (is_empty())
return 0;
node *temp = head;
return (temp->data);
}
Parsing of decimal points is probably best fixed by adding a switch statement.
You really have a new state once you see a decimal point. See the code below. I have also added code to handle '-' character. I use the pow() math function to add in the decimal part of the number. I would move the number parsing into a function, but did not want to completely change your code. Here is the full solution:
#include <cmath>
#include <iostream>
using namespace std;
struct node {
float data;
node *next;
};
class stack {
private :
node *head;
public :
stack()
{
head = NULL;
}
void push(float a)
{
node *temp = new node();
temp->data = a;
temp->next = head;
head = temp;
}
float pop()
{
node *temp = head;
head = temp->next;
float a = temp->data;
delete temp;
return a;
}
float see_top()
{
if (is_empty())
return 0;
node *temp = head;
return (temp->data);
}
int is_empty()
{
if (head == NULL)
return 1;
else
return 0;
}
};
bool is_digit(char a)
{
return (a >= '0' && a <= '9') || a == '.' || a == '-';
}
bool is_operand(char a)
{
switch (a) {
case '+' :
case '-' :
case '*' :
case '/' :
case '^' : return true;
default : return false;
}
}
float operation(float a, float b, char sym)
{
float ans;
switch (sym) {
case '+' : ans = a + b;
break;
case '-' : ans = a - b;
break;
case '*' : ans = a * b;
break;
case '/' : ans = a / b;
break;
case '^' : ans = pow(a, b);
break;
default : break;
}
return ans;
}
int main()
{
char exp[100];
stack s;
float num = 0, num1 = 0, num2 = 0;
int l, i;
cout << "Enter the posfix expression : ";
cin.getline(exp, 100);
l = strlen(exp);
for (i = 0; i < l; i++) {
int exponent = 0;
int sign = 1;
if (is_digit(exp[i])) {
num = 0;
while (exp[i] != ' ') {
switch (exp[i]) {
case '.':exponent = -1;
break;
case '-':
sign = -1; // handle the negative sign
break;
default:int a = exp[i] - '0';
if(exponent >= 0) {
num = pow(10, exponent) * num + a;
++exponent;
} else {
num = pow(10, exponent) * a + num;
--exponent;
}
}
++i;
}
num *= sign; // If there was a '-', multiply by -1
s.push(num);
} else if (is_operand(exp[i])) {
num2 = s.see_top();
s.pop();
num1 = s.see_top();
s.pop();
num = operation(num1, num2, exp[i]);
s.push(num);
} else
continue;
}
num = s.see_top();
s.pop();
cout << "Answer : " << num;
return 0;
}
Alternative Solution Using std::istringstream
For a little extra fun, I rewrote some of the input processing to use std::istringstream. stringstream is very powerful, and should always be considered when doing parsing. I find that the string to double conversion functions in c++ is confusing and error prone. So, if you are allowed to use stringstream, this may be helpful. It removes the need to search for decimal points because stringstream will do the conversion for you. it will handle all the edge cases. Here is the stringstream solution:
#include <iostream>
#include <cmath>
#include <sstream>
using namespace std;
struct node {
float data;
node *next;
};
class stack {
private :
node *head;
public :
stack()
{
head = NULL;
}
void push(float a)
{
node *temp = new node();
temp->data = a;
temp->next = head;
head = temp;
}
float pop()
{
node *temp = head;
head = temp->next;
float a = temp->data;
delete temp;
return a;
}
float see_top()
{
if (is_empty())
return 0;
node *temp = head;
return (temp->data);
}
bool is_empty()
{
if (head == NULL)
return true;
else
return false;
}
};
int is_digit(char a)
{
if (a >= '0' && a <= '9')
return 1;
else
return 0;
}
int is_operand(char a)
{
switch (a) {
case '+' :
case '-' :
case '*' :
case '/' :
case '^' : return 1;
default : return 0;
}
}
float operation(float a, float b, char sym)
{
float ans;
switch (sym) {
case '+' : ans = a + b;
break;
case '-' : ans = a - b;
break;
case '*' : ans = a * b;
break;
case '/' : ans = a / b;
break;
case '^' : ans = pow(a, b);
break;
default : break;
}
return ans;
}
int main()
{
// char exp[100];
stack s;
float num = 0, num1 = 0, num2 = 0;
cout << "Enter the posfix expression : ";
std::string input_line;
std::getline(cin, input_line);
std::istringstream token_stream(input_line); // Parse words from input_line
std::string token;
while (token_stream >> token) {
// Check the first character of the token. It is n operand, then use it
// You could move the size() check to the is_operand() function
if (token.size() == 1 && is_operand(token[0])) {
char operand = token[0];
num2 = s.see_top();
s.pop();
num1 = s.see_top();
s.pop();
num = operation(num1, num2, operand);
s.push(num);
} else {
std::istringstream number_stream(token); // convert number tokens to floats
if(number_stream >> num) {
s.push(num);
}
}
}
num = s.see_top();
s.pop();
cout << "Answer : " << num;
return 0;
}
Related
I want to sort a list by last names with the algorithm of Quicksort but when exchanging the elements it does not work, it leaves them as they were
In this part the values of the chains are exchanged
void swap(string* a, string* b){
cout<<"A and B are "<<*a<<" - "<<*b<<endl;
string t = *a;
*a = *b;
cout<<" A is ->"<<*a<<endl;
*b= t;
cout<<"B is ->"<<*b<<endl;
}
This is where the partition is made. I have noticed that when * i and * j take values they are exactly the same names and therefore can not be compared later. It seems strange to me that this list works if it is a number but when it is strings this error occurs.
User *i = lower;
But this did not work at the end because the program crashed, but if you change the value of the string
User* partition(User *lower, User *high){
cout<<"Lower -> "<<lower->lastname<<endl;
cout<<"High -> "<<high->lastname<<endl;
string pivot = high->lastname;
User *i = bajo->prev;
for (User *j = lower; j != high; j = j->next)
{
if (j->lastname.compare(pivot)< 0)
{
i = (i == NULL)? lower : i->next;
cout<<"Atention J e I valen ->"<<i->lastname<<" - "<<j->lastname<<endl;
swap(&(i->lastname), &(j->lastname));
}
}
i = (i == NULL)? lower : i->lastname; // Similar to i++
swap(&(i->lastname), &(alto->lastname));
return i;
}
What am I failing? How can I make it really take the desired value.
EDITED:
This is the source code
#include <iostream>
#include<iomanip>
#include <string>
#include<cstdlib>
using namespace std;
class User
{
public :
string lastname;
User *next;
User *prev;
User()
{
lastname= "";
next=NULL;
prev=NULL;
}
int empty(User *listt)
{
if(listt == NULL)
{
return 1;
}
else
{
return 0;
}
}
User *Insert(User *listt, string lastName)
{
User *temp = new User();
if(empty(listt))
{
temp->lastname=lastName;
listt = temp;
}
else
{
temp->lastname=lastName;
listt->prev=temp;
temp->next=listt;
listt=temp;
}
return listt;
}
void swap(string* a, string* b)
{
string t = *a;
*a = *b;
*b= t;
}
User* partition(User* lower, User* high)
{
cout<<"Lower -> "<<lower->lastname<<endl;
cout<<"High -> "<<high->lastname<<endl;
string pivot = high->lastname;
User *i = lower->prev;
for (User *j = lower; j != high; j = j->next)
{
if (j->lastname.compare(pivot)< 0)
{
i = (i == NULL)? lower : i->next;
swap(&(i->lastname), &(j->lastname));
}
}
i = (i == NULL)? lower : i->next; // Similar to i++
swap(&(i->lastname), &(high->lastname));
return i;
}
User *Last(User *listt)
{
User *temp = listt;
while(temp && temp ->next)
temp=temp->next;
return temp;
}
void _quickSort( User* lower, User* high)
{
if(high != NULL && lower != high&&lower!= high->next)
{
User *p = partition(lower,high);
_quickSort(lower,p->next); //I change this part
_quickSort(p->next,high);
}
}
void quickSort(User *listt)
{
User *h = Last(listt);
_quickSort(listt, h);
}
User *Display(User *listt)
{
if(empty(listt))
{
cout<<"List empty"<<endl;
}
else
{
User *temp = new User();
temp = listt;
while(temp!= NULL)
{
cout<<"The last name is -> "<<temp->lastname<<endl;
temp=temp->next;
}
}
return listt;
}
};
int main()
{
User *listt = NULL;
User y;
bool exit = false;
int opc;
string lastName;
while(!exit)
{
cout<<"1.-Insert an element"<<endl;
cout<<"2.-Sort element-(Quicksort)"<<endl;
cout<<"3.-Show elements"<<endl;
cout<<"4.-Exitt"<<endl;
cin>>opc;
switch(opc)
{
case 1:
cout<<"Inser your last name"<<endl;
cin>>lastName;
listt=y.Insert(listt,lastName);
system("pause");
system("cls");
break;
case 2:
cout<<"Sorting...."<<endl;
y.quickSort(listt);
system("pause");
system("cls");
break;
case 3:
cout<<"Display..."<<endl;
y.Display(listt);
system("pause");
system("cls");
break;
case 4:
exit = true;
break;
}
}
}
Actually your swap function seems working but string t = *a; usage is kind of weird because *a is considered as an int value so you should not assign it to a string although the compiler can handle it either way. On the other hand I guess what you mentioned is to copy the value of "a" into a temporary string and it should be done as string* t = a; and then you can do b = t; but instead of that passing by reference is a better practice such as
void swap(string &a, string &b){
string t = a;
a = b;
b= t;
}
and you may want to check your Quick-sort implementation, see the reference on this page
_quickSort(lower,p->next); //I change this part
This should be p->prev. The correct function:
void _quickSort(User* lower, User* high)
{
if(high != NULL && lower != high&&lower != high->next)
{
User *p = partition(lower, high);
_quickSort(lower, p->prev); //change it back!
_quickSort(p->next, high);
}
}
Additionally there is resource leak in Display. Don't allocate new items in display function:
User *Display(User *listt)
{
if(empty(listt))
{
cout<<"List empty"<<endl;
}
else
{
//User *temp = new User(); <== don't allocate new item here
User *temp = listt;
while(temp!= NULL)
{
cout<<"The last name is -> "<<temp->lastname<<endl;
temp=temp->next;
}
}
return listt;
}
Testing with a 1000 items:
class User
{
public:
class Node
{
public:
string lastname;
Node *next;
Node *prev;
Node()
{
prev = next = nullptr;
}
};
Node *head;
User()
{
head = nullptr;
}
void Insert(string val)
{
Node *temp = new Node;
temp->lastname = val;
if (head)
{
head->prev = temp;
temp->next = head;
}
head = temp;
}
void swap(string &a, string &b)
{
string t = a;
a = b;
b = t;
}
Node *Tail()
{
Node *temp = head;
while(temp && temp->next)
temp = temp->next;
return temp;
}
Node* partition(Node* left, Node* right)
{
string pivot = right->lastname;
Node *i = left->prev;
for(Node *j = left; j != right; j = j->next)
{
if(j->lastname < pivot)
{
i = (i == nullptr) ? left : i->next;
swap(i->lastname, j->lastname);
}
}
i = (i == nullptr) ? left : i->next; // Similar to i++
swap(i->lastname, right->lastname);
return i;
}
void quickSort(Node* left, Node* right)
{
if(!left || !right || left == right || left == right->next)
return;
Node *p = partition(left, right);
quickSort(left, p->prev);
quickSort(p->next, right);
}
void quickSort()
{
quickSort(head, Tail());
}
void Display()
{
string last;
for (Node *n = head; n; n = n->next)
{
if(n->lastname < last)
{
cout << "error ***\n";
break;
}
last = n->lastname;
cout << n->lastname << endl;
}
}
};
int main()
{
User list;
list.Insert("z");
list.Insert("c");
list.Insert("a");
list.Insert("g");
for(int i = 0; i < 1000; i++)
{
string str;
for (int j = 0; j < 3; j++)
str.push_back('a' + rand() % 26);
list.Insert(str);
}
list.quickSort();
list.Display();
return 0;
}
Disclaimer: This is homework and I am pretty much a complete beginner in programming (only took an intro class to C a few years ago). If it matters, this is from a Competitive Programming class. I appreciate all feedback besides on the question itself like good programming practices, naming conventions...etc. I am new to coding, but love it and want to improve.
Consider n lists that are initialized with a single member that corresponds to its list number, i.e.:
#1: 1
#2: 2
#3: 3
...
Input:
First line contains n m where 1 ≤ n ≤ 1000000, 1 ≤ m ≤ 2000000;
Followed by m lines of k a b, where k is either 0 or 1 and denotes the type of manipulation:
k = 0: find member a and move from its position to behind member b
k = 1: move the entire list of #a list and place it behind the #b list
Output:
Print the lists in order after all the commands are executed. The question specifically states no whitespaces at the end of each line.
What I've tried:
#include <iostream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
class List {
private:
struct Node {
int data;
Node *next;
};
Node *head;
public:
List() {
head = NULL;
}
Node *GetHead() {
return head;
}
Node *GetPrevNode(int value) { // Gets the previous node to the node I am trying to move
Node *temp, *peek;
temp = head;
peek = temp->next;
if (head->data == value)
return head;
else {
while (peek != NULL) {
if (peek->data == value) {
return temp;
}
else {
temp = temp->next;
peek = temp->next;
}
}
return NULL;
}
return NULL;
}
Node *GetNode(int value) { // Gets the actual node I'm trying to move
Node *temp;
temp = head;
while (temp != NULL) {
if (temp->data == value) {
return temp;
}
else {
temp = temp->next;
}
}
return NULL;
}
void PushNode(int value) {
Node *temp = new Node;
temp->data = value;
temp->next = NULL;
if (head == NULL) {
head = temp;
}
else {
head->next = temp;
}
}
void MoveNode(Node *prevFrom, int value, Node *dest) { // called on the FROM list
Node *tempDestNext, *from;
tempDestNext = dest->next;
if (prevFrom->data == value) {
from = prevFrom;
}
else {
from = prevFrom->next;
}
//different cases
if (dest->next == from) {
return;
}
else if (from->next == dest) {
from->next = dest->next;
dest->next = from;
if (from == prevFrom) {
head = dest;
}
else {
prevFrom->next = dest;
}
}
else {
Node *tempFromNext;
tempFromNext = from->next;
dest->next = from;
if (from == head) {
head = tempFromNext;
}
else {
prevFrom->next = tempFromNext;
}
from->next = tempDestNext;
}
}
void ConcList(Node *headFrom) { // called on the DESTINATION list
if (head == NULL) {
head = headFrom;
}
else {
Node *temp;
temp = head;
while (temp != NULL) {
if (temp->next == NULL) {
temp->next = headFrom;
break;
}
else {
temp = temp->next;
}
}
}
}
void PrintList() {
Node *temp;
temp = head;
while (temp != NULL) {
cout << " " << temp->data;
temp = temp->next;
}
}
};
struct Move {
int type, from, to;
};
void MarkNodePos(vector<int> &NodePos, int type, int from, int to) { // record on which list a node is
switch (type) {
case 0:
NodePos[from - 1] = NodePos[to - 1];
break;
case 1:
for (int i = 0; i < NodePos.size(); i++) {
if (NodePos[i] == (from - 1)) {
NodePos[i] = (to - 1);
}
}
break;
}
}
int RandomNum(int min, int max) {
int range = max - min + 1;
int num = rand() % range + min;
return num;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); // my teacher told us to include this code for speed optimization
int n, m;
cin >> n >> m;
cin.ignore();
vector<List> line;
for (int i = 0; i < n; i++) {
List temp;
temp.PushNode(i + 1);
line.push_back(temp);
}
vector<int> NodePos;
for (int i = 0; i < n; i++) {
NodePos.push_back(i);
}
string instrc;
Move step;
srand(time(NULL));
for (int i = 0; i < m; i++) {
int mode = 0; // switch between input and testing mode
switch (mode) {
case 0: {
getline(cin, instrc);
stringstream ss(instrc);
ss >> step.type >> step.from >> step.to;
break;
}
case 1:
stringstream ss;
ss << RandomNum(0, 1) << " " << RandomNum(1, n) << " " << RandomNum(1, n);
ss >> step.type >> step.from >> step.to;
cout << step.type << " " << step.from << " " << step.to << endl;
break;
}
if (step.from != step.to) {
switch (step.type) {
case 0:
int from, to;
from = NodePos[step.from - 1];
to = NodePos[step.to - 1];
line[from].MoveNode(line[from].GetPrevNode(step.from), step.from, line[to].GetNode(step.to));
MarkNodePos(NodePos, step.type, step.from, step.to);
break;
case 1:
if (line[step.from - 1].GetHead() != NULL) {
line[step.to - 1].ConcList(line[step.from - 1].GetHead());
List clear;
line[step.from - 1] = clear;
MarkNodePos(NodePos, step.type, step.from, step.to);
}
break;
}
}
}
for (int i = 0; i < n; i++) {
cout << "#" << (i + 1) << ":";
line[i].PrintList();
if (i != (n - 1))
cout << "\n";
}
return 0;
}
An example:
Input:
6 4
0 4 3
0 6 5
1 2 5
1 6 5
Output:
#1: 1
#2:
#3: 3 4
#4:
#5: 5 6 2
#6:
I keep getting wrong answer from the judge but as you can seen, I used a random number generator to test out my program and from my testing it all seems fine. I really have no clue what to look for. What could be causing the error?
I am really stuck in make conversion of special prefix to postfix operation on our task, let me describe the task similarly :
We have such operation to use as operations in our prefixes, here is the method that i am checking them :
bool isOperator(string c)
{
if (c == "log" || c == "exp" || c == "sum" || c == "div" || c == "abs" || c == "sqrt" || c == "sub" || c == "product" || c == "max" || c== "min" || c == "mod" ) // you may add operator here
return true;
return false;
}
Anyway example prefix instructions can have parentheses to make operation precedence, this is what I am stuck at. I know, I need to implement such a recursion, but i can't find a way.
div ( sqrt 5 ) 3
Output should be
5 sqrt 3 div
Another example :
div ( sum ( exp 2 3 ) ( sqrt 5 ) ) 3
Output
2 3 exp 5 sqrt sum 3 div
Every operation, parentheses or number should have space between elements in assumed condition.
My stack implementation
Stack.h
#include<iostream>
using namespace std;
struct node {
string op ;
node *next;
};
struct Stack {
node * head;
void create();
void close();
void push (node *);
node* pop();
node* top();
bool isEmpty();
};
Stack.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "stack.h"
#include <iostream>
#include <stdlib.h>
void Stack::create() {
head = NULL;
}
void Stack::close() {
node *p;
while (head) {
p = head;
head = head->next;
//delete [] p->data;
delete p;
}
}
void Stack::push(node *newdata) {
node *newnode = new node;
newnode = newdata;
newnode->op = newdata->op;
newnode->next = head;
head = newnode;
}
node *Stack::pop() {
if (isEmpty())
return NULL;
node *topnode = head;
head = head->next;
//delete topnode;
return topnode;
}
node *Stack::top() {
if (isEmpty())
return NULL;
node *topnode = head;
//delete topnode;
return topnode;
}
bool Stack::isEmpty() {
return (head == NULL);
}
as #PaulMcKenzie mentioned, i've tried an implementation below, sub_array string array contains the word list without spaces.
bool isLeftParanthesis(string c)
{
if (c == "(" ) // you may add operator here
return true;
return false;
}
bool isRightParanthesis(string c)
{
if (c == ")") // you may add operator here
return true;
return false;
}
int main()
{
string prefix;
getline(cin, prefix);
istringstream iss(prefix);
istringstream iss2(prefix);
int count1 = 0, count2 = 0;
string postfix = "";
Stack *st = new Stack;
string t1, t2;
string sub;
string *sub_array;
while (iss >> sub) {
count1++;
}
sub_array = new string[count1];
while (iss2 >> sub) {
sub_array[count2] = sub;
count2++;
}
int l = count1;
int right_p_count = 0;
for (int i = 0; i < count1; i++)
{
if (isRightParanthesis(sub_array[i]))
{
right_p_count++;
}
}
string *postfixes = new string[right_p_count];
int index_right_p = 0;
for (int i = 0; i < count1; i++) {
while (!isRightParanthesis(sub_array[i]))
{
node *n = new node;
n->op = sub_array[i];
st->push(n);
i++;
if (i == count1)
{
break;
}
}
if( i != count1){
if (isRightParanthesis(sub_array[i])) {
postfix = "";
while (!isLeftParanthesis(st->top()->op))
{
string t = st->pop();
if (!isOperator(t) && !isLeftParanthesis(t) && !isRightParanthesis(t)) {
postfix = t + " " + postfix;
}
else if (isOperator(t)) {
postfix = postfix + " " + t;
}
}
st->pop();
postfixes[index_right_p] = postfix;
index_right_p++;
}
}
postfix = "";
while ( !st->isEmpty() && index_right_p == right_p_count && i == count1)
{
string t = st->pop();
if (!isOperator(t) && !isLeftParanthesis(t) && !isRightParanthesis(t)) {
postfix = t+" "+postfix;
}
else if (isOperator(t)) {
postfix = postfix+""+t;
}
else {
break;
}
}
}
string result = "";
for (int i = 0; i < right_p_count; i++)
{
result = result + "" + postfixes[i];
}
result = result + " " + postfix;
cout << result << endl;
}
Variable postfix refers to output postfix, but my output is not wrong for some of the operations such as :
div ( sqrt 5 ) 3
When i saw a parantheses i am checking if it is left or right, using right one for trigger.
abs ( product -2 -4 -8 )
Expected output is :
-2 -4 -8 product abs
UPDATE : I solved stack problem myself, but found out that, algorithm calculates some expressions wrongly...
Example expression :
3 2 3 exp sum
Expected output :
sum 3 ( exp 2 3 )
My output :
2 3 exp 3 sum
My algorithm which is using right parentheses as triggers calculates it wrongly and I don't know how to implement this control into that, are there any suggestions ?
I need to create a RPN (postfix notation) calculator which makes simple operations (+, -, *, /), while using a linked list to maintain the stack. I have got the majority of it done but am running into a few problems. I can calculate any two numbers with one operand (ex: 5 5 + = 10), but cannot do anything more than that. I have done some research online, and watched a few YouTube videos to get where I am at now, but most use the stack reference to do it. I have tried to combine tutorials on that, along with how to make my own stack.
I am quite new to this and am pretty lost on how to calculate a larger expression (ex: 5 5 5 + + = 15), and I also need to check for errors, which I have completed some, but the ones I'm struggling with are "too many operators," and "too many operands." With too many operators I'm assuming it has something to do with not being able to pop off a value because there isn't one there, but that's as far as I can get (if it's right, still not quite sure how to implement it). Any help with any of these 3 things, or anything else you can see here would greatly be appreciated.
#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;
}
}
}
First I would recommend you use std::map<double> instead of rolling your own linked list, unless it is for learning purposes.
The main problem is in SLLNode::popVal() and SLLNode::print() where things got a little bit confused.
Here is what you need to change to fix it:
double popVal()
{
SLLNode *next = top -> ptr;
double ret = top -> data;
delete top;
top = next;
return ret;
}
void print()
{
cout << "= " << top -> data << endl << ">>";
}
There are many other things you could improve in your code but that should answer your question.
You have two operators, '*' and '+' in your expression to calculate multiplication. I have added & rearranged a bit of error checking,
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;
}
Define a list node that contains head/tail, and counts the elements in your stack,
#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 << ">>";
}
};
Your stack implementation leaks memory, allocates unnecessary nodes, and is missing a couple of useful stack operations that will help you solve some of your problems. You need a destructor that empties your list in case you forget to empty it, and it would help to have a print the entire list. Anyway,
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();
}
};
You might want to add more operators, extract that,
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;
}
Check your stacksize prior to extracting items from your stack,
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;
}
You need some way to print your list. The forth language used ".", so here I have added a case to print the list using ".",
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;
}
}
}
I also cleaned up a couple of other errors.
I am writing a code that evaluates a given Postfix expression. Each operand and operator is separated by a blank space and the last operator is followed by a blank space and an 'x'.
Example:
Infix expression: (2*3+4)*(4*3+2)
Postfix expression: 2 3 * 4 + 4 3 * 2 + * x
"x" implies the end of expression.
The input (Postfix expression) is given as a string from by another function that converts an infix expression to a postfix expression.
The function for postfix evaluation is:
int pfeval(string input)
{
int answer, operand1, operand2, i=0;
char const* ch = input.c_str();
node *utility, *top;
utility = new node;
utility -> number = 0;
utility -> next = NULL;
top = new node;
top -> number = 0;
top -> next = utility;
while((ch[i] != ' ')&&(ch[i+1] != 'x'))
{
int operand = 0;
if(ch[i] == ' ') //to skip a blank space
i++;
if((ch[i] >= '0')&&(ch[i] <= '9')) //to gather all digits of a number
{
while(ch[i] != ' ')
{
operand = operand*10 + (ch[i]-48);
i++;
}
top = push(top, operand);
}
else
{
top = pop(top, operand1);
top = pop(top, operand2);
switch(ch[i])
{
case '+': answer = operand2 + operand1;
break;
case '-': answer = operand2 - operand1;
break;
case '*': answer = operand2 * operand1;
break;
case '/': answer = operand2 / operand1;
break;
case '^': answer = pow(operand2, operand1);
break;
}
top = push(top, answer);
}
i++;
}
pop(top, answer);
cout << "\nAnswer: " << answer << endl;
return 0;
}
The output for the example I've given should be "140" but what I get is "6". Please help me find the error.
The push and pop methods are as follows (in case somebody wants to review):
class node
{
public:
int number;
node *next;
};
node* push(node *stack, int data)
{
node *utility;
utility = new node;
utility -> number = data;
utility -> next = stack;
return utility;
}
node* pop(node *stack, int &data)
{
node *temp;
if (stack != NULL)
{
temp = stack;
data = stack -> number;
stack = stack -> next;
delete temp;
}
else cout << "\nERROR: Empty stack.\n";
return stack;
}
while((ch[i] != ' ')&&(ch[i+1] != 'x'))
You drop out of this loop as soon as a) the current character is a space, or b) the next character is 'x'. The current character becomes a space pretty early in the process; you only process a small portion of the string.
Try comparing with the following code.
#include<iostream>
using namespace std;
#include<conio.h>
#include<string.h>
#include<math.h>
class A
{
char p[30],ch;
int i,top,s[30],y1,y2,x,y,r;
public:
A()
{
top=-1;
i=0;
}
void input();
char getsymbol();
void push(int);
int pop();
void evaluation();
};
void A :: input()
{
cout<<"enter postfix expression\n";
gets(p);
}
char A :: getsymbol()
{
return p[i++];
}
void A :: push(int ch)
{
if(top==29)
cout<<"stack overflow\n";
else
s[++top]=ch;
}
int A :: pop()
{
if(top==-1)
{
cout<<"stack underflow\n";
return 0;
}
else
return s[top--];
}
void A :: evaluation()
{
ch=getsymbol();
while(ch!='\0')
{
if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')
{
cout<<"enter the value for "<<ch;
cin>>x;
push(x);
}
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='^')
{
y2=pop();
y1=pop();
if(ch=='+')
{
y=y1+y2;
push(y);
}
else if(ch=='-')
{
y=y1-y2;
push(y);
}
else if(ch=='^')
{
y=y1^y2;
push(y);
}
else if(ch=='*')
{
y=y1*y2;
push(y);
}
else if(ch=='/')
{
y=y1/y2;
push(y);
}
else
{
cout<<"entered operator has no value\n";
}
}
ch=getsymbol();
}
if(ch=='\0')
{
r=pop();
cout<<"the result is "<<r;
}
}
int main()
{
A a;
int m=0;
while(m==0)
{
a.input();
a.evaluation();
cout<<"enter 0 to continue 1 to exit\n";
cin>>m;
}
getch();
return 0;
}