Problems Calculating a Postfix Expression with More Than Two Operands - c++

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.

Related

Cannot find source of segmentation fault

I have been working on this assignment for sometime and cannot figure out what is causing the segmentation fault, any help would be appreciated, here is a copy of my two files!
I am also in the process of fixing my inFile setup, but I would rather focus on that after the fact of the segmentation error.
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include "source.cpp"
using namespace std;
void scanFile(string fileName);
void printActors(string movie);
void printShows(string actor);
const int MAX_LINE = 128;
int movies = 0;
BST tree;
int main(){
// Scan file
scanFile("tvDB.txt");
// Print all the show titles
cout << "All show titles:" << endl;
tree.displayShows();
cout << endl; // Whitespace
// Print actors /w given show
cout << "Actors from 'The Saint'" << endl;
printActors("The Saint");
// Print show /w given actor
printShows("Tim Conway");
// Print from decade
return 0;
}
// Trims the line removing all excess whitespace before and after a sentence
string isolateLine(string line)
{
int index = 0, start = 0, end = 0;
//Get the start of the line
for(int i = 0; i < line.length(); i++)
{
if(line[i] != ' ' && line[i] != '\t')
{
start = i;
break;
}
}
// Get the end of the line
for(int x = line.length(); x >= 0; x--)
{
if(line[x] != ' ' && line[x] != '\t')
{
end = x;
break;
}
}
// Trim line
line = line.substr(start, end);
return line;
}
// A boolean that returns if the tree is blank, useful for skipping a line and continuing to search for a movie
bool blankLine(string line){
for(int i = 0; i < line.length(); i++)
{
if(line[i] != ' ' && line[i] != '\t')
{
return false;
}
}
return true;
}
// Prints all the shows an actor has starred in
void printShows(string actor){
cout << "Shows with [" << actor << "]:" << endl;
tree.displayActorsShows(actor);
cout << endl; // whitespace
}
// Prints all the actors in a particular movie
void printActors(string show)
{
cout << " Actors for [" << show << "]" << endl;
tree.displayActors(show);
cout << endl;
}
// Scans the fild and categorizes every line of data into the proper categories of the show
void scanFile(string fileName)
{
ifstream inFile;
inFile.open("tvDB.txt");
list <string> actors;
string line = "";
string title = "";
string year = "";
while(getline(inFile, line))
{
line = isolateLine(line);
if(!blankLine(line))
{
// Get movie title
if(line.find('(') != std::string::npos)
{
title = line.substr(0, line.find('(')-1);
}
// Get movie year
if (line.find('(') != std::string::npos) {
year = line.substr(line.find('(') + 1, line.find(')'));
year = year.substr(0, year.find(')'));
}
// Add to actors list
actors.push_back(line);
}
else
{
if(!actors.empty()) // pops the title
{
actors.pop_front();
}
}
tree.insert(title, year, actors);
actors.clear();
movies++;
}
}
and
#include <iostream>
#include <list>
using namespace std;
class BST
{
// Defines the main components of the node object, as well as refrences the left and right elements
struct node
{
string show;
string year;
string genre;
string URL;
list <string> actors;
node*left;
node*right;
};
node* root;
// Deletes all the nodes of the tree
node* makeEmpty(node* t)
{
if(t == NULL)
{
return NULL;
}
else
{
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
return NULL;
}
// Inserts a node in the tree
node* insert(string x, string year, list<string> actors, node* t)// DO not include Genrem or URL
{
if(t == NULL)
{
t = new node;
t->show = x;
t->year = year;
t->actors = actors;
t->left = t->right = NULL;
}
else if(x < t-> show)
{
t->left = insert(x, year, actors, t->left);
}
else if(x > t-> show)
{
t->right = insert(x, year, actors, t->left);
}
else
{
return t;
}
}
//Finds the minimum most node to the left
node* findMin(node* t)
{
if(t == NULL)
{
return NULL;
}
else if(t->left == NULL)
{
return t;
}
else
{
return findMin(t->left);
}
}
// Finds the maximum most node to the right
node* findMax(node* t)
{
if(t == NULL)
{
return NULL;
}
else if(t->right == NULL)
{
return t;
}
else
{
return findMax(t->right);
}
}
// Finds a node with the given parameters
node* find(node* t, string x )
{
if(t == NULL)
{
return NULL;
}
else if(x.at(0) < t-> show.at(0))
{
return find(t->left, x);
}
else if(x.at(0) > t->show.at(0))
{
return find(t->right, x);
}
else
{
return t;
}
}
// Prints out the shows inorder
void inorder(node* t)
{
if(t == NULL)
{
// Do nothing
}
else
{
inorder(t->left);
cout << "- " << t->show << endl;
inorder(t->right);
}
}
// Prints the shows of a given actor
void findShow(node* t, string person, list<string> &list)
{
if(t == NULL)
{
// Do nothing
}
else
{
while(!t->actors.empty())
{
if(t->actors.front() == person)
{
list.push_front(t->show);
break;
}
t->actors.pop_front();
}
findShow(t->left, person, list);
findShow(t->right, person, list);
}
}
// Prints the shows within a given year
void findYear(node* t, string year, list<string> &list)
{
if(t == NULL)
{
// Do nothing
}
else
{
if(t->year == year)
{
list.push_front(t->show);
}
findYear(t->left, year, list);
findYear(t->right, year, list);
}
}
public:
BST()
{
root = NULL;
}
~BST()
{
root = makeEmpty(root);
}
// Public calls to modify the tree
// Inserts a node with the given parametersremove
void insert(string x, string year, list<string> actors)
{
root = insert(x, year, actors, root);
}
// Removes a node with the given key
// void remove(string x, node* t)
// {
// root = remove(x, root);
// }
// Displays all shows within the tree
void displayShows()
{
inorder(root);
}
// Displays all the actors with a given show
void displayActors(string show)
{
root = find(root, show);
if(root != NULL) // THIS LINE
{
list<string> temp = root-> actors;
while(!temp.empty())
{
cout << "- " << temp.front() << endl;
temp.pop_front();
}
}
else
{
cout << "root is NULL." << endl;
}
}
// Displays the shows of a given actor
void displayActorsShows(string actor)
{
list<string> show;
findShow(root, actor, show);
while(!show.empty())
{
cout << "- " << show.front() << endl;
show.pop_front();
}
}
// Searches the tree with the given node
void search(string x)
{
root = find(root, x);
}
};// end of class
I would suggest using a debugger (like GDB for unix or the VisualStudioBuildIn Debugger). There the SEG Fault is indicated in which variable the seg fault will be.
Also look out for correct initialized pointers (at least with = nullptr)
Btw: try to use nullptr instead of NULL, since it is not typesafe to use NULL.
Here is why: NULL vs nullptr (Why was it replaced?)

AVL-tree node misses content of an included structure and I cannot find why

Consider the following AVL-tree implementation. Each node contains a list of numbers.The key is named workload, but consider it as a plain double variable. If a key is equal to the key of an already existing node, the number gets pushed into the list. Every time I pop a number from a list, I perform a check, if the node's list is empty -> remove the node. But, after the element with key=3 gets removed completely, the list of the node with key=4 is suddenly empty. I've been trying to solve it for over 10 hours now, it's actually the first time I ever needed to ask something here. Pardon me if I miss a few things.
#include<iostream>
#include <list>
using namespace std;
class BST
{
struct node
{
double workload;
list<int> numbers;
node* left;
node* right;
int height;
};
node* root;
unsigned long long size;
bool empty;
void makeEmpty(node* t)
{
if(t == NULL)
return;
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
node* insert(double workload,int number, node* t)
{
if(t == NULL)
{
t = new node;
t->workload = workload;
t->numbers.push_back(number);
t->height = 0;
t->left = t->right = NULL;
}
else if(t->workload == workload){
t->numbers.push_back(number);
}
else if(workload < t->workload)
{
t->left = insert(workload, number, t->left);
if(height(t->left) - height(t->right) == 2)
{
if(workload < t->left->workload)
t = singleRightRotate(t);
else
t = doubleRightRotate(t);
}
}
else if(workload > t->workload)
{
t->right = insert(workload, number, t->right);
if(height(t->right) - height(t->left) == 2)
{
if(workload > t->right->workload)
t = singleLeftRotate(t);
else
t = doubleLeftRotate(t);
}
}
//if x == t->workload instead of using int workload. its a list and we push into it.
t->height = max(height(t->left), height(t->right))+1;
return t;
}
node* singleRightRotate(node* &t)
{
node* u = t->left;
t->left = u->right;
u->right = t;
t->height = max(height(t->left), height(t->right))+1;
u->height = max(height(u->left), t->height)+1;
return u;
}
node* singleLeftRotate(node* &t)
{
node* u = t->right;
t->right = u->left;
u->left = t;
t->height = max(height(t->left), height(t->right))+1;
u->height = max(height(t->right), t->height)+1 ;
return u;
}
node* doubleLeftRotate(node* &t)
{
t->right = singleRightRotate(t->right);
return singleLeftRotate(t);
}
node* doubleRightRotate(node* &t)
{
t->left = singleLeftRotate(t->left);
return singleRightRotate(t);
}
node* findMin(node* t)
{
if(t == NULL)
return NULL;
else if(t->left == NULL)
return t;
else
return findMin(t->left);
}
node* findMax(node* t)
{
if(t == NULL)
return NULL;
else if(t->right == NULL)
return t;
else
return findMax(t->right);
}
node* find(node* t,double workload){
if (t->workload == workload){
return t;
}
else if(workload < t->workload && t->left!=NULL)
return find(t->left,workload);
else if(workload > t->workload && t->right!=NULL)
return find(t->right,workload);
else{
cout << "Null node encountered" << endl;
return t;
}
}
node* remove(double x, node* t)
{
node* temp;
// Element not found
if(t == NULL)
return NULL;
// Searching for element
if(x < t->workload)
t->left = remove(x, t->left);
else if(x > t->workload)
t->right = remove(x, t->right);
// Element found
// With 2 children
else if(t->left && t->right)
{
temp = findMin(t->right);
t->workload = temp->workload;
t->right = remove(t->workload, t->right);
}
// With one or zero child
else
{
temp = t;
if(t->left == NULL)
t = t->right;
else if(t->right == NULL)
t = t->left;
delete temp;
}
if(t == NULL)
return t;
t->height = max(height(t->left), height(t->right))+1;
// If node is unbalanced
// If left node is deleted, right case
if(height(t->left) - height(t->right) == -2)
{
// right right case
if(height(t->right->right) - height(t->right->left) == 1)
return singleLeftRotate(t);
// right left case
else
return doubleLeftRotate(t);
}
// If right node is deleted, left case
else if(height(t->right) - height(t->left) == 2)
{
// left left case
if(height(t->left->left) - height(t->left->right) == 1){
return singleRightRotate(t);
}
// left right case
else
return doubleRightRotate(t);
}
return t;
}
int height(node* t)
{
return (t == NULL ? -1 : t->height);
}
int getBalance(node* t)
{
if(t == NULL)
return 0;
else
return height(t->left) - height(t->right);
}
void inorder(node* t)
{
if(t == NULL)
return;
inorder(t->left);
cout << t->workload<< " ";
inorder(t->right);
}
//Reverse inorder (Sorted highest to lowest)
void rinorder(node* t)
{
if(t == NULL)
return;
rinorder(t->right);
cout << t->workload << " ";
rinorder(t->left);
}
void preorder(node* t)
{
if (t == NULL)
return;
cout << t->workload << " ";
preorder(t->left);
preorder(t->right);
}
void postorder(node* t)
{
if (t == NULL)
return;
postorder(t->left);
postorder(t->right);
cout << t->workload << " ";
}
public:
BST()
{
root = NULL;
}
void insert(double workload, int number)
{
root = insert(workload, number, root);
}
void remove(double workload)
{
root = remove(workload, root);
}
void displayrin()
{
cout << "Rinorder: ";
rinorder(root);
cout << endl;
}
void displayin()
{
cout << "Inorder: ";
inorder(root);
cout << endl;
}
void displaypost()
{
cout << "Postorder: ";
postorder(root);
cout << endl;
}
void displaypre()
{
cout << "Preorder: ";
preorder(root);
cout << endl;
}
double getMax(){
return findMax(root)->workload;
}
int getMaxNum(){
return find(root,getMax())->numbers.front();
}
int getNum(double workload){
return find(root,workload)->numbers.front();
}
//We pop a Num from a node
void popnumber(double workload){
node *t = find(root,workload);
if(t!=NULL){
if(!t->numbers.empty()){
t->numbers.pop_front();
//If the Num list of the node is empty, remove node
if(t->numbers.empty()){
remove(t->workload);
}
}
}
}
};
int main()
{
BST t;
//key value pairs
t.insert(2,1);
t.insert(3,1);
t.insert(3,2);
t.insert(4,7);
cout << t.getNum(4) << endl;
cout << t.getNum(3)<<endl;
t.popnumber(3);
cout << t.getNum(3)<<endl;
t.popnumber(3);
t.displayin();
t.displaypost();
t.displaypre();
t.displayrin();
cout << t.getNum(4) << endl;
cout << "The max is : " << t.getMax() << endl;
cout << "The top Num of the Max is : " << t.getMaxNum() << endl;
return 0;
}
As mentioned in the comments, the problem is in the "Element found With 2 children" section of remove.
To remove the element, you find the next element in the tree. Your implementation then wants to copy the contents of the found node (temp). You copy the workload value, so that both t and temp have the same workload value (4). You do not copy the numbers list. The t node has a workload of 4 and an empty numbers list, while temp has a workload of 4 and a numbers list consisting of one element, 7. You then delete temp, losing the list.
One fix would be to copy (or move) numbers from temp to t before removing it from the tree. Adding a MoveData method to node that would move the data fields (while not altering the tree specific fields) would make it easier to add new data fields.
Another fix would be to change how you're doing the data update. If you update all pointers (and other tree related fields like height), then you don't have to worry about the data (and any pointers/iterators to the nodes would not be invalidated).

EXC_BAD_ACCESS with stack/list c++

I am working on my RPN calculator project.
At this moment I would like to put all the numbers from an entered calculation on stack, but unfortunately the process finishes with exit code 11 and I am stuck. It extacly happens when I type for example 3, and then 3+3.
I debugged it and I can see that the problem is in the line:
if(header!= nullptr) {
in here:
cell* List::Last() {
if(header!= nullptr) {
cell *i;
for(i = header; i->next != nullptr; i = i->next);
return i;
}
else return nullptr;
}
Exception EXC_BAD_ACCESS. I suppose it has something to do with my header in the list, but I have no idea why. I have read about this exception but it still doesn't help me. As far as I can see, most people get it with arrays. I would be very grateful for any hints... My full code is here (it is not finished yet, so it might seem that there is a lot of useless methods):
#include <iostream>
using namespace std;
typedef int element;
struct cell
{
element element;
cell * next;
};
class List {
protected:
cell * header;
public:
List();
~List();
void Insert(element x, cell * p);
void Delete(cell * p);
element Retrieve(cell * p);
cell * Locate(element x);
cell * First();
cell * Next(cell * p);
cell * Previous(cell * p);
cell * Last();
void print();
bool empty() {
return header == nullptr;
}
};
List::List() {
header = nullptr;
}
List::~List() {
cell *tmp;
while(header != nullptr) {
tmp = header;
header = header->next;
delete tmp;
}
}
void List::Insert(element x, cell * p) {
cell *tmp;
if (p != nullptr) {
tmp = p->next;
p->next = new cell;
p->next->element = x;
p->next->next = tmp;
} else {
header = new cell;
header->element = x;
header->next = nullptr;
}
}
element List::Retrieve(cell * p) {
return p->element;
}
void List::Delete(cell *p) {
cell* tmp;
tmp=p->next;
p->next = p->next->next;
delete tmp;
}
void List::print() {
for (cell *i = header; i != nullptr; i = i->next) {
cout << i->element << endl;
}
}
cell* List::Locate(element x) {
cell* tmp;
tmp = header;
while(tmp->next != nullptr) {
if(tmp->next->element == x) return tmp;
tmp = tmp->next;
}
return tmp;
}
cell* List::First() {
return header;
}
cell* List::Last() {
if(header!= nullptr) {
cell *i;
for(i = header; i->next != nullptr; i = i->next);
return i;
}
else return nullptr;
}
cell* List::Next(cell *p) {
return p->next;
}
cell* List::Previous(cell *p) {
cell* tmp;
tmp = header;
while(tmp->next != p) tmp = tmp->next;
return tmp;
}
class Stack {
List * list;
public:
Stack();
element top();
element pop();
void push(element x);
bool empty();
void makenull();
};
Stack::Stack() {
list = new List();
}
element Stack::top() {
return this->list->Retrieve(this->list->Last());
}
element Stack::pop() {
int tmp = this->list->Retrieve(this->list->Last());
cell* c = this->list->Previous(list->Last());
this->list->Delete(c);
return tmp;
}
void Stack::push(element x) {
this->list->Insert(x, this->list->Last());
}
bool Stack::empty() {
return this->list->empty();
}
void Stack::makenull() {
delete list;
}
class RPN {
Stack *stack;
public:
RPN();
int type;
int result;
char calculation[];
int menu();
int calculate();
bool isNum(char c);
bool isOperand(char c);
void putOnStack();
void enterCalculation();
void convertToRPN();
void convertFromRPN();
};
RPN::RPN() {
stack = new Stack();
type = 0;
result = 0;
}
int RPN::menu() {
cout << endl << "Choose option:" << endl;
cout << "1. Convert to RPN" << endl;
cout << "2. Convert from RPN" << endl;
cout << "3. RPN calculator" << endl;
cout << "4. Regular calculator" << endl;
cout << "5. Finish" << endl;
cin >> type;
switch (type) {
case 1:
enterCalculation();
convertFromRPN();
break;
case 2:
enterCalculation();
convertToRPN();
break;
case 3:
enterCalculation();
convertFromRPN();
calculate();
break;
case 4:
enterCalculation();
calculate();
break;
case 5:
break;
default:
cout << "Nie ma takiej opcji!" << endl;
break;
}
return type;
}
bool RPN::isNum(char c) {
return isdigit(c);
}
bool RPN::isOperand(char c) {
return c == '+' || c == '-' || c == '/' || c == '*';
}
void RPN::putOnStack() {
for(int i = 0; i < strlen(calculation); i++)
if(isNum(calculation[i])) stack->push(calculation[i]);
}
void RPN::enterCalculation() {
cout << "Type your calculation:" << endl;
cin >> calculation;
putOnStack();
}
void RPN::convertToRPN() {
}
void RPN::convertFromRPN() {
}
int RPN::calculate() {
return result;
}
int main() {
auto *rpn = new RPN();
while(rpn->type != 5)
rpn->menu();
return 0;
}
try this:
cell* List::Last() {
cell *i = header;
while(i->next != nullptr && i != nullptr)i=i->next;
return i;
}
Thank you for all your help. I managed to cope with that problem.
Maybe this will help somebody, I post my code below.
#include <iostream>
using namespace std;
typedef string element;
struct cell {
string element;
cell * next;
};
class List {
public:
cell * header;
List();
~List();
element Retrieve(cell * p);
cell* Previous(cell * p);
cell * Last();
void Insert(const element &x, cell * p);
void Delete(cell * p);
bool empty() {
return header == nullptr;
}
};
List::List() {
header = nullptr;
}
List::~List() {
cell *tmp;
while(header != nullptr) {
tmp = header;
header = header->next;
delete tmp;
}
}
element List::Retrieve(cell * p) {
return p->element;
}
void List::Delete(cell *p) {
cell* tmp;
if(p->next == nullptr) {
cout << "Error! No next element to delete!" << endl;
} else if(p->next->next == nullptr) {
delete p->next;
p->next = nullptr;
} else {
tmp = p->next;
p->next = p->next->next;
delete tmp;
}
}
cell* List::Previous(cell *p) {
if(p == header) {
cout << "There is no previous element for the header!" << endl;
return nullptr;
} else {
if(header -> next == p) {
return header;
} else {
cell *tmp = header;
while(tmp->next != p) tmp = tmp->next;
return tmp;
}
}
}
void List::Insert(const element &x, cell * p) {
cell *tmp;
if (p != nullptr) {
if(p -> next == nullptr) {
p->next = new cell;
p->next->element = x;
p->next->next = nullptr;
} else {
tmp = p->next;
p->next = new cell;
p->next->element = x;
p->next->next = tmp;
}
} else {
header = new cell;
header->element = x;
header->next = nullptr;
}
}
cell* List::Last() {
if(header != nullptr) {
if(header-> next == nullptr) return header;
else {
cell *i;
for(i = header; i->next != nullptr; i = i->next);
return i;
}
}
else return nullptr;
}
class Stack {
public:
List * list;
Stack();
void push(const element &x);
void makenull();
bool empty();
element pop();
element top();
};
Stack::Stack() {
list = new List();
}
void Stack::makenull() {
this->list->header = nullptr;
}
bool Stack::empty() {
return this->list->empty();
}
element Stack::top() {
return this->list->Retrieve(this->list->Last());
}
element Stack::pop() {
string tmp;
if(list->Last() == list->header) {
tmp = this->list->header->element;
this->list->header = nullptr;
} else {
tmp = this->list->Retrieve(this->list->Last());
cell* c = this->list->Previous(list->Last());
this->list->Delete(c);
}
return tmp;
}
void Stack::push(const element &x) {
if(this->list->header != nullptr) {
this->list->Insert(x, this->list->Last());
} else {
this->list->header = new cell;
this->list->header->element = x;
this->list->header->next = nullptr;
}
}
class RPN {
public:
RPN();
~RPN();
Stack *stack;
int type;
string calculation;
int menu();
string convertToRPN();
string convertFromRPN();
double calculateRPN();
void enterCalculation();
bool isNum(string s);
bool isOperator(char c);
int compareOperators(string op1, string op2);
};
RPN::RPN() {
stack = new Stack();
type = 0;
}
RPN::~RPN() {
delete stack;
}
int RPN::menu() {
cout << endl << "Choose option:" << endl;
cout << "1. Convert from RPN" << endl;
cout << "2. Convert to RPN" << endl;
cout << "3. RPN calculator" << endl;
cout << "4. Calculator" << endl;
cout << "5. Exit" << endl;
cin >> type;
cin.ignore();
switch (type) {
case 1:
enterCalculation();
convertFromRPN();
break;
case 2:
enterCalculation();
convertToRPN();
break;
case 3:
enterCalculation();
calculateRPN();
break;
case 4:
enterCalculation();
calculation = convertToRPN();
calculateRPN();
break;
case 5:
break;
default:
cout << "No such option! Choose a correct one." << endl;
break;
}
return type;
}
bool RPN::isNum(string s) {
return !s.empty() && std::find_if(s.begin(), s.end(), [](char c) { return !isdigit(c); }) == s.end();
}
bool RPN::isOperator(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/');
}
int RPN::compareOperators(string op1, string op2) {
if ((op1[0] == '*' || op1[0] == '/') && (op2[0] == '+' || op2[0] == '-')) return -1;
else if ((op1[0] == '+' || op1[0] == '-') && (op2[0] == '*' || op2[0] == '/')) return 1;
return 0;
}
void RPN::enterCalculation() {
calculation[0] = 0;
cout << "Input expression:" << endl;
getline(cin, calculation);
}
string RPN::convertToRPN() {
auto len = static_cast<int>(calculation.length());
stack->makenull();
string RPNcalc;
RPNcalc.clear();
int j = 0;
int par1 = 0;
int par2 = 0;
while(isspace(calculation[j])) j++;
if(!isNum(string(1, calculation[j])) && (calculation[j] != '(')) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
j = 0;
while(isspace(calculation[len-1-j])) j++;
if(!isNum(string(1, calculation[len-1-j])) && (calculation[len-1-j] != ')')) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
for (int i = 0; i < len; i++) {
if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
if(isspace(calculation[i+1])) {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else {
if(isNum(string(1, calculation[i])) && calculation[i+1] != '.' && !isNum(string(1, calculation[i]))) {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else if(isOperator(calculation[i+1])) {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else if(calculation[i+1] == ')') {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else {
RPNcalc.push_back(calculation[i]);
}
}
} else if (isOperator(calculation[i])) {
while(!stack->empty() && stack->top()[0] != '(' && compareOperators(stack->top(), string(1, calculation[i])) <= 0) {
RPNcalc.push_back(stack->pop()[0]);
RPNcalc.push_back(' ');
}
stack->push(string(1, calculation[i]));
} else if(calculation[i] == '(') {
par1++;
stack->push(string(1, calculation[i]));
} else if(calculation[i] == ')') {
par2++;
while(!stack->empty()) {
if(stack->top()[0] == '(') {
stack->pop();
break;
}
RPNcalc.push_back(stack->pop()[0]);
RPNcalc.push_back(' ');
}
} else if(isspace(calculation[i])) {
} else {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
}
if(par1 != par2) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
while(!stack->empty()) {
if(RPNcalc.back() != ' ') RPNcalc.push_back(' ');
RPNcalc.push_back(stack->top()[0]);
stack->pop();
}
if(type != 4) cout << "RPN expression: " << RPNcalc << endl;
return RPNcalc;
}
string RPN::convertFromRPN() {
auto len = static_cast<int>(calculation.length());
stack->makenull();
string num;
string right;
string left;
string newExpr;
int j = 0;
while(isspace(calculation[j])) j++;
if(!isNum(string(1, calculation[j]))) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
j = 0;
while(isspace(calculation[len-1-j])) j++;
if(!isOperator(calculation[len-1-j])) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
for (int i = 0; i < len; i++) {
if (isOperator(calculation[i])) {
right = stack->pop();
left = stack->pop();
newExpr.clear();
newExpr += '(';
newExpr += left;
newExpr += ' ';
newExpr += calculation[i];
newExpr += ' ';
newExpr += right;
newExpr += ')';
stack->push(newExpr);
} else if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
if(isspace(calculation[i+1])) {
num.push_back(calculation[i]);
stack->push(num);
num.clear();
} else num.push_back(calculation[i]);
} else if(isspace(calculation[i])) {
} else {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
}
newExpr = stack->top();
newExpr.erase(newExpr.begin());
newExpr.erase(newExpr.end()-1);
cout << "Infix notation: " << newExpr;
return newExpr;
}
double RPN::calculateRPN() {
auto len = static_cast<int>(calculation.length());
stack->makenull();
double a = 0;
double b = 0;
double result = 0;
string num;
num.clear();
if(isNum(string(1, calculation[len-1]))) {
cout << "Expression incorrect!" << endl;
return 0;
}
for (int i = 0; i < len; i++) {
if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
if(isspace(calculation[i+1])) {
num.push_back(calculation[i]);
stack->push(num);
num.clear();
} else num.push_back(calculation[i]);
} else if (isOperator(calculation[i])) {
a = stod(stack->pop());
b = stod(stack->pop());
switch (calculation[i]) {
case '*':
stack->push(to_string(a * b));
break;
case '/':
stack->push(to_string(b / a));
break;
case '-':
stack->push(to_string(b - a));
break;
case '+':
stack->push(to_string(a + b));
break;
default:
break;
}
} else if(isspace(calculation[i])) {
} else {
cout << "Expression incorrect!" << endl;
return 0;
}
}
result = stod(stack->pop());
if(!stack->empty()) {
cout << "Expression incorrect!" << endl;
return 0;
}
cout << "Result: " << result << endl;
return result;
}
int main() {
cout << endl << "POSTFIX-INFIX CALCULATOR AND CONVERTER "<< endl;
auto *rpn = new RPN();
while(rpn->type != 5)
rpn->menu();
return 0;
}

Output of c++ program not coming as expected

I have made a C++ program for a binary tree. But the terminal is not asking the statement for inputting the direction for where the elements are to be placed.
Also when I replace the statement from " node *temp = new node " to "node *temp=NULL" the program stops working .
#include <iostream>
#include <cstring>
using namespace std;
class node {
int data;
node * left;
node * right;
public:
node * level_order(node * first);
node * create_bt(node * first);
void display(node * first);
};
//node *first=NULL;
node * node::create_bt(node * first) {
node * temp = new node;
int ele;
//char dir;
cout << "\n Enter data ";
cin >> ele;
temp->data = ele;
temp->left = NULL;
temp->right = NULL;
if (first == NULL) {
temp = first;
return first;
} else {
char dir[20];
cout << "\n Enter the direction ";
cin >> dir;
node * cur = first;
int j = 0;
while (dir[j] != '\0') {
if (dir[j] == 'l') {
cur = cur->left;
}
if (dir[j] == 'r') {
cur = cur->right;
}
j++;
}
cur = temp;
return first;
}
}
void node::display(node * first) {
if (first == NULL)
return;
cout << "\n " << first->data;
display(first->left);
display(first->right);
}
int main() {
int n;
node s;
node * first = NULL;
cout << "\n No of elements ";
cin >> n;
for (int i = 0; i < n; i++) {
first = s.create_bt(first);
}
s.display(first);
return 0;
}
first=s.create_bt(first); does not changes state, from NULL to 'l' or 'r'. You have to change that.
node*node::create_bt(node *first)
{
node *temp=new node;
int ele;
//char dir;
cout<<"\n Enter data ";
cin>>ele;
temp->data=ele;
temp->left=NULL;
temp->right=NULL;
char dir[20];
cout<<"\n Enter the direction ";
cin>>dir;
if(first==NULL)
{
temp=first;
return first;
}
else
{
node*cur=first;
int j=0;
while(dir[j]!='\0')
{
if(dir[j]=='l')
{
cur=cur->left;
}
if(dir[j]=='r')
{
cur=cur->right;
}
j++;
}
cur=temp;
return first;
}
}
I believe you re looking something like this. This is a basic binary tree, i had to make a basic one in order to understand how it works and how it chooses left and right. I make a class inside a class, in order to have access to my data members (node class, int data, *left , *right) and have them at the same time protected, all-in-one. As you can see "newnode" just creates a node and NULL s the pointers. Thats it. "Find" searches and finds a node with a current key, and returns it when exits. All the rest, i guess, you can understand them, as they are prety much the same with your code. The only thing you have to do is to define, when you want to direct the node you want. REMINDER: You have to find a way to utilize it, so the leafs will not end far-left or far-right.("Enter the direction"). I hope i helped you understand.
#include <iostream>
#include <conio.h>
using namespace std;
class mybTree {
class node {
public:
int data;
node * left;
node *right;
};
node *root;
node *newnode(int num){
node *newnode1;
newnode1 = new (nothrow) node;
newnode1->data = num;
newnode1->left = NULL;
newnode1->right = NULL;
return newnode1;
}
public:
node *find (int key) {
node *current;
current = root;
while (current->data !=key){
if (key<current->data){
current = current->left;
} else {
current = current->right;
}
if (current == NULL){
return NULL;
}
}
return NULL;
}
void display (node *ptr);
void display_tree();
bool insert(int num);
void post_order_delete(node *ptr);
mybTree();
~mybTree();
};
int main(){
char ch = ' ';
int a;
mybTree mybTree1;
while (ch !='0'){
cout << "0->Exit"<<endl<< "1-> add"<<endl<< "2-> find" <<endl<<"3-> Show me the tree\n";
ch = getch();
switch (ch) {
case '0':
break;
case '1':
cout << "number";
cin >> a;
if (!mybTree1.insert(a)){
cout << "Not enough memory" << endl;
}
break;
case '2' :
cout << "Number:" ;
cin >> a;
if (mybTree1.find(a)!=NULL) {
cout << "Found" << endl;
} else {
cout << "Not existed" << endl;
}
break;
case '3':
mybTree1.display_tree();
cout<<endl;
break;
default:
cout << "Wrong Message";
break;
}
}
return 0;
}
void mybTree::display(node *ptr) {
if (ptr == NULL){
return;
}
display(ptr->left);
cout << ptr->data<<endl;
display(ptr->right);
}
void mybTree::display_tree() {
//Displays the Tree
display(root);
}
bool mybTree::insert(int num) {
//It inserts a node. Desides left or right.
node *next,*current,*ptr;
int isleft;
next = current = root;
ptr = newnode(num);
if (ptr == NULL) {
return false;
}
if (root == NULL) {
root = ptr;
return true;
}
while (1){
if (num < current->data){
next = current->left;
isleft = 1;
} else {
next = current->right;
isleft = 0;
}
if (next == NULL){
if (isleft){
current->left = ptr;
} else {
current->right = ptr;
}
return true;
}
current=next;
}
return false;
}
void mybTree::post_order_delete(node *ptr) {
//deletes the node. Usefull for destructor
if (ptr == NULL){
return;
}
post_order_delete(ptr->left);
post_order_delete(ptr->right);
cout << ptr->data;
delete ptr;
}
mybTree::mybTree() {
//Constructor
root = NULL;
}
mybTree::~mybTree() {
//Destructor
post_order_delete(root);
root = NULL;
}

Infix to Postfix to Output (Postfix Calculator) using stacks

Good day, everyone! I'm new in C++ (and here in stackoverflow as well) and I need help from you experts.
I have here a code that should ask the user for the infix expression then converts it to postfix and outputs the result (postfix calculator). However, I cannot convert postfix to output instantly so as soon as it displays the postfix expression, it asks for the postfix expression again (with spaces after e.g., 1 2 + ) before outputting the real answer.
There is no error or warning but when I run the program, the computer says "file.exe has stopped working" after displaying the postfix expression. So the program is able to convert infix to postfix expression correctly but there is still some jinx when displaying the output.
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
struct node {
char data;
node *next;
};
node *top=NULL;
node *bottom=NULL;
node *key;
node *last;
node *before_last;
void push (const char Symbol) {
key = new node;
key->data = Symbol;
key->next = top;
top = key;
}
void push_for_output (node* &stack, int key) {
node* newNode = new node;
newNode->data = key;
newNode->next = stack;
stack = newNode;
}
const char pop() {
if (!top) {
cout << "Stack underflow\n" << endl;
return ' ';
}
node* key = top;
top = top->next;
char ch = key->data;
delete key;
return ch;
}
int pop_for_output (node* &stack) {
int key = stack->data;
node* nodeToDelete = stack;
stack = stack->next;
delete nodeToDelete;
return key;
}
bool isOperator (char *token) {
if (strcmp(token, "+") == 0) {
return true;
}
else if (strcmp(token, "-") == 0) {
return true;
}
else if (strcmp(token, "*") == 0) {
return true;
}
else if (strcmp(token, "/") == 0) {
return true;
}
else {
return false;
}
}
const bool is_empty() {
return !top;
}
int postfix(const char *infix) {
char infix_ch[100]={NULL};
char postfix_ch[100]={NULL};
node* stack = NULL;
strcpy(infix_ch,"(");
strcat(infix_ch, infix);
strcat(infix_ch,")");
char symbol[5]={NULL};
char temp[5]={NULL};
for(int i=0; i<strlen(infix_ch); i++) {
symbol[0]=infix_ch[i];
if(symbol[0]=='(')
push(symbol[0]);
else if(symbol[0]==')') {
symbol[0]=pop( );
while(symbol[0]!='(') {
strcat(postfix_ch, symbol);
symbol[0]=pop( );
}
}
else if(symbol[0]=='^' || symbol[0]=='*' || symbol[0]=='/' || symbol[0]=='+' || symbol[0]=='-') {
if(symbol[0]=='*' || symbol[0]=='/') {
temp[0]=pop( );
while(temp[0]=='^' || temp[0]=='*' || temp[0]=='/') {
strcat(postfix_ch, temp);
temp[0]=pop( );
}
push(temp[0]);
}
else if(symbol[0]=='+' || symbol[0]=='-') {
temp[0]=pop( );
while(temp[0]!='(') {
strcat(postfix_ch, temp);
temp[0]=pop( );
}
push(temp[0]);
}
push(symbol[0]);
}
else
strcat(postfix_ch, symbol);
}
cout << "Postfix: " << postfix_ch;
char postfix[80];
cout << "\nEnter postfix expression (include spaces between each operand and/or operator): ";
cin.getline(postfix, 80);
char *tokens = strtok(postfix, " ");
while (tokens != NULL) {
if (isOperator (tokens)) {
int operand2 = pop_for_output(stack);
int operand1 = pop_for_output(stack);
int result;
if (strcmp(tokens, "+") == 0) {
result = operand1 + operand2;
}
else if (strcmp(tokens, "-") == 0) {
result = operand1 - operand2;
}
else if (strcmp(tokens, "*") == 0) {
result = operand1 * operand2;
}
else if (strcmp(tokens, "/") == 0) {
result = operand1 / operand2;
}
push_for_output (stack, result);
}
else {
push_for_output (stack, atoi (tokens));
}
tokens = strtok(NULL, " ");
}
cout << pop_for_output(stack);
system("pause");
return 0;
}
int main( ) {
char infix_values[100]={NULL};
cout << "Enter the infix equation: ";
cin >> infix_values;
postfix(infix_values);
}
I'm a newbie and I really need help from you experts. I will really appreciate it if you help me correct my program. Thank you very much and have a nice day!
One possible issue is that the pop_for_output() function never checks for an empty/NULL stack like you do in pop(). If an invalid postfix expression is entered, or if your parsing is incorrect, you could very easily get into the case of referencing a NULL pointer which could very well explain the crash.