I am trying to write a function that evaluates simple mathematical expressions (only four operations). I used stack and vector to do this. But stack operations don't behave as I expect. I couldn't find the cause. I am open to different solutions.
The function should take a string like this:
"5 * 44 + 3 / 2 * 4 - 12"
And return the result as a double.
#include <iostream>
#include <vector>
#include <stack>
#include <string>
#include <cstdlib>
using namespace std;
vector<string> split(const std::string& str, char delim = ' ')
{
vector<string> elements;
stringstream ss(str);
string token;
while (getline(ss, token, delim)) {
elements.push_back(token);
}
return elements;
}
double evaluate(string operation)
{
vector<string> values = split(operation, ' ');
stack<string> result_stack;
double result = 0;
for(unsigned int i = 0; i < values.size(); i++){
if(values[i] == "*"){
double mini_result = stod(result_stack.top()) * stod(values[i+1]);
result_stack.pop();
i++;
result_stack.push(to_string(mini_result));
}
else if(values[i] == "/"){
double mini_result = stod(result_stack.top()) / stod(values[i+1]);
result_stack.pop();
i++;
result_stack.push(to_string(mini_result));
}
else{
result_stack.push(values[i]);
}
}
for(unsigned int i = 0; i<result_stack.size(); i++){
if(result_stack.top() == "-"){
result_stack.pop();
result = stod(result_stack.top()) - result;
result_stack.pop();
}
else if(result_stack.top() == "+"){
result_stack.pop();
result += stod(result_stack.top());
result_stack.pop();
}
else{
result += stod(result_stack.top());
result_stack.pop();
}
}
return result;
}
int main()
{
cout<<evaluate("5 * 44 + 3 / 2 * 4 - 12");
}
Before the second for loop, values in the result_stack should be like this for this example. "12 | - | 6 | + | 220" . And the returning value should be 214.
But before the second for loop, stack contains only "12 | - | 6" values. "+" and "220" values are not there. Some extra pops occur which I don't expect.
stack content should be like this for this example
Your operands for the subtraction operation are swapped. This because when you process the stack for the + and - operations you're parsing the equation from right-to-left.
With your example, when the - is found in the stack, result is 12. You pop the -, then subtract the 6, leaving 6 in result when it should be -6.
You should use
result = stod(result_stack.top()) - result;
for subtraction.
There is also no error checking in your code for invalid equations.
Answered here: answer of the question
Completed code is here:
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
#include <stack>
using namespace std;
string trim(const string& str)
{
size_t first = str.find_first_not_of(' ');
if (string::npos == first)
{
return str;
}
size_t last = str.find_last_not_of(' ');
return str.substr(first, (last - first + 1));
}
vector<string> split(const std::string& str, char delim = ' ')
{
vector<string> elements;
stringstream ss(str);
string token;
while (getline(ss, token, delim)) {
elements.push_back(token);
}
return elements;
}
double evaluate(string operation)
{
vector<string> values = split(operation, ' ');
vector<string> result_vector;
double result = 0;
for(unsigned int i = 0; i < values.size(); i++){
if(values[i] == "*"){
double mini_result = stod(result_vector.back()) * stod(values[i+1]);
result_vector.pop_back();
i++;
result_vector.push_back(to_string(mini_result));
}
else if(values[i] == "/"){
double mini_result = stod(result_vector.back()) / stod(values[i+1]);
result_vector.pop_back();
i++;
result_vector.push_back(to_string(mini_result));
}
else{
result_vector.push_back(values[i]);
}
}
auto iterator = result_vector.begin();
while(iterator != result_vector.end()){
if(*iterator == "-"){
iterator++;
result -= stod(*iterator);
}
else if(*iterator == "+"){
iterator++;
result += stod(*iterator);
}
else{
result += stod(*iterator);
}
iterator++;
}
return result;
}
int main()
{
cout<<evaluate("5 * 44 + 3 / 2 * 4 - 12");
}
Related
I'm having trouble with getting this code to work properly.
It's purpose is to show the middle word of any given sentence. If its an even amount of words, it shows the first word out of the 2. Instead of printing the middle word, it prints the 2 middle characters. I think its only a few small things I have to add, but I'm stuck on this roadblock. Any help would be appreciated, thank you!
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string sentence="";
string letter="";
string middle="";
int count=0;
int spacecount=0;
int mid=0;
cout << "Enter a sentence:" << endl;
getline(cin,sentence); //gets user input
//for example, "hello there friend"
for(int count =0; count<sentence.length();count++){
letter=sentence.substr(count,1);
if(letter!=" "){
count++;
}
if(letter==" "){
spacecount++;
}
if(count> mid){
mid = count;
}
if (((mid = sentence.length() / 2) % 2) == 0){ //checks if amount of words is even
middle=sentence.substr(mid,2);
}
if (((mid = sentence.length() / 2) % 2) >= 1) //checks if amount of words is odd
{
middle=sentence.substr(mid,2);
}
}
reverse(middle.rbegin(),middle.rend()); //makes it so the word isnt backwards
cout <<"Middle word is: " << middle <<endl;
//shows middle word to user
//it should print "there", but it shows "he" (the two middle characters)
return 0;
}
Lets split the string into tokens and find the middle object of it?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char **argv) {
string input;
getline(cin, input);
vector<string> tokens;
string token;
for (size_t i = 0; i < input.length(); i++) {
char c = input[i];
if (c == ' ' || !input[i + 1]) {
if (!input[i + 1])
token += c;
tokens.push_back(token);
token = "";
continue;
}
token += c;
}
auto mid = tokens.size() % 2 == 0 ? tokens.begin() + tokens.size() / 2 - 1
: tokens.begin() + tokens.size() / 2;
cout << *mid;
return 0;
}
void pairStar(char input[]) {
int len = strlen(input);
if(input[0] == '\0'){
return ;
}
if(input[0] == input[1]){
for(int i = len; i >= 2; i--){
input[i] = input[i-1];
}
input[2] = input[1];
input[1] = '*';
}
pairStar(input+1);
}
what is the mistake in this code. I couldn't find out.
if I entered aaaa, abaa etc. it runs perfect.
but when i entered scatter is shows scat*ter?#
so what is the perfect solution ?
input string is aaaa . so output is a*a*a*a instead of a*aa*a.
You do not copy terminating character \0!
So when you have inserted a character termination of string is undefined.
Note also that proper answer for aaaa should be a*a*a*a (or a*aa*a depending on problem definition).
Split argument to define soruce and destination and use separate buffers.
void copyAddStarToPairs(const char *src, char *dst)
{
*dst = *src;
if (!*dst) return;
dst++;
char prev = *src++;
if (prev = *src) *dst++ = '*';
copyAddStarToPairs(src, dst);
}
May be you should use std::string as your char buffer may not be long enough.
#include <string>
using std::string;
void pairStar(string & s, int st) {
if (st >= (int)s.size() - 1)
return;
else if (s[st] == s[st + 1]) {
s += ' ';
for (int i = (int)s.size() - 1; i > st + 1; i--)
s[i] = s[i - 1];
s[st + 1] = '*';
st++;
}
pairStar(s, st + 1);
}
int main() {
string s = "aadqwedabbbbb*dqwdasd";
pairStar(s, 0);
cout << s << endl;
}
Add the line input[len+1]='\0'; after the lineinput[1]='*';.
What happens actually is that once you append '*',you aren't appending the '\0' character. This line will append it to the end that means string end here for the first call that you made. So recursive function will also do the same, it will add '\0' character at the end letting know that string ends here.
Consider an example:
aa is a string of length 2 and and after adding star the length of string will become 3 so input[len+1] will be input[2+1]=input[3].
So character next to the moved character will be '\0' character everytime.
PS: this is my first time adding an answer on stackoverflow...
I offer to solve this problem, using the algorithm Depth first search.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int maximumSize=40;
string symbols="aadqwedabbbbb*dqwdasd";
string symbolsNew;
vector<int> visited(maximumSize, 0);
template<class Type>
void showContent(Type input)
{
for(int index=0; index<input.size(); ++index)
{
cout<<input[index];
}
return;
}
void depthFirstSearch(int current, int previous)
{
if(visited[current]==1)
{
return;
}
visited[current]=1;
symbolsNew.push_back(symbols[current]);
int interactions=0;
for(int next=(current+1); next<symbols.size(); ++next)
{
if(interactions!=0)
{
break;
}
if(symbols[current]==symbols[next])
{
symbolsNew.push_back('*');
}
++interactions;
}
for(int next=current; next<symbols.size(); ++next)
{
depthFirstSearch(next, current);
}
return;
}
void solve()
{
depthFirstSearch(0, -1);
cout<<"symbols <- ";
showContent(symbols);
cout<<endl<<"symbolsNew <- ";
showContent(symbolsNew);
return;
}
int main()
{
solve();
return 0;
}
Here is the result:
symbols <- aadqwedabbbbb*dqwdasd
symbolsNew <- a*adqwedab*b*b*b*b*dqwdasd
void pairStar(char input[]) {
int len = strlen(input);
if(input[0] == '\0'){
return ;
}
if(input[0] == input[1]){
for(int i = len+1; i >= 2; i--){
input[i] = input[i-1];
}
input[2] = input[1];
input[1] = '*';
}
pairStar(input+1);
}
void helper(char input[], int start)
{
if (input[start] == '\0')
{
return;
}
helper(input, start + 1);
if (input[start] == input[start + 1])
{
for (int i = strlen(input); i >= start + 1; i--)
{
input[i + 1] = input[i];
}
input[start + 1] = '*';
}
}
void pairStar(char input[])
{
helper(input, 0);
}
I am trying to split specific string with couple of different ways. The example of my input is (-5,3,0,1,-2).
And this is my first code,
// code 1
string s = "(-5,3,0,1,-2)";
int j = 0;
int * temp = new int[s.length()];
for (int i = 0; i < s.length(); i++) {
if (s[i] != '(' && s[i] != ',' && s[i] != ')') {
temp[j++] = (s[i]-'0');
}
}
code 1 works well except, it converts - sign to ascii value(45) not negative int value.
//code2
char *first = _strdup(s.c_str());
char * temp2 = NULL;
char *temp = strtok_s(first, "(,)", &temp2);
/* Expected output is
temp[0] = -5
temp[1] = 3
temp[2] = 0
temp[3] = 1
temp[4] = -2
*/
However middle of debugging, temp contains ascii value, not string value. Also not sure code2 is correctly working.
Thanks in advances!
You need a proper string to int conversion. Use std::stoi. I used the boost tokenizer. It is very handy for your case.
#include <string>
#include <boost/tokenizer.hpp>
#include <vector>
using namespace std;
using namespace boost;
int main() {
vector<int> intList
string text = "(-5,3,0,1,-2)";
char_separator<char> sep(",");
tokenizer<char_separator<char>> tokens(text, sep);
for (const auto& t : tokens)
intList.push_back(std::stoi(t));
}
PS. you forgot the delete for you new. Please use a proper container (e.g. std::vector).
Use istrstream::get method. You can avoid the open and close braces by replacing those.
void _parse_(istrstream &str,string &strText, char ch = ',')
{
char chText[MAX_PATH];
str.get(chText, MAX_PATH,ch);
str.get(ch);
strText = chText;
}
string s = "(-5,3,0,1,-2)";
istrstream inputStream(s);
string sTemp;
//Replace here the open and close braces.
do
{
_parse_(inputStream, sTemp,',');
//Your value in sTemp
}while(!sTemp.empty())
If you need use c++ without any library, you can use flowing code:
#include <string>
#include <vector>
using namespace std;
int main()
{
string s = "(-5 2,3 0 1, 0 , 1 , -21 0 )";
int location = 0;
vector<int> array;
string sub;
while (location <= s.length())
{
if ((s[location] >= 48 && s[location] <= 57) || s[location] == 45 || s[location] == 32)
{
if (s[location] != 32)
{
sub += s[location];
}
}
else
{
if (sub.length() != 0)
{
std::string::size_type sz;
int num = stoi(sub, &sz);
array.push_back(num);
}
sub.clear();
}
location++;
}
return 0;
}
#include <sstream>
#include <iomanip>
using namespace std;
const string INTEGER_CHARS {"0123456789+-"};
vector<int> readIntFromString(const string src) {
const char stopFlag{'\0'};
const string str {src + stopFlag};
vector<int> numbers;
stringstream ss(str);
int tmp;
for(char nextChar = ss.peek(); nextChar != stopFlag; nextChar = ss.peek()) {
if (INTEGER_CHARS.find(nextChar) != string::npos) {
ss >> setbase(0) >> tmp;
numbers.push_back(tmp);
} else {
ss.ignore();
}
}
return numbers;
}
setbase(0): make >> operator to recognize other based numbers, e.g. 0b01, 070, 0xF
ss.ignore(): skip the char we don't care
You can use the following,
string s = "(-5,3,0,1,-2)";
int j = 0;
string temp;
std::vector<int> values;
for (int i = 0; i < s.length(); i++)
{
if (s[i] != '(' && s[i] != ')')
{
while (s[i] != ',' && s[i] != ')')
{
temp += s[i];
++i;
}
values.push_back(std::atoi(temp.c_str()));
temp.clear();
}
}
This is my code:
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string userInput;
std::getline(std::cin, userInput);
int sum;
int result;
std::string numDigit;
bool space = true;
for (int i = 0; i < userInput.length(); i++) {
if (isdigit(userInput[i]) && space) {
numDigit += userInput[i];
space = false;
}else if(isdigit(userInput[i]) && !space) {
numDigit += userInput[i];
}else if (!isdigit(userInput[i]) && !space) {
std::stringstream(numDigit) >> result;
sum += result;
numDigit = "";
result = 0;
space = true;
}
std::cout << sum;
}
}
If i input 1 2 3 with space, it should ouput sum = 6, but instead it output many digits of number why is it like that ? (sorry I'm beginner of c++)
You are using your variables sum and result without initializing them.
When you are using any compiler, you cannot assume that variables will be automatically initialized to zero. So, if you use an uninitialized variable, the behavior of your program will be undefined, it might be just nice the value you want, or it will be filled with garbage values like 80123901723012, -190283812791, etc...
int sum = 0;
int result = 0;
Declare a variable and initialize it to zero is always a good practice.
EDIT :
The problem your code have is:
1. you should only output sum after for loop end.
2. your should check for i <= userInput.length() instead of checking for less than only.
modified code:
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string userInput;
std::getline(std::cin, userInput);
int sum = 0;
int result = 0;
std::string numDigit = "";
bool space = true;
for (int i = 0; i <= userInput.length(); i++) {
if (isdigit(userInput[i]) && space) {
numDigit += userInput[i];
space = false;
}
else if (isdigit(userInput[i]) && !space) {
numDigit += userInput[i];
}
else if (!isdigit(userInput[i]) && !space) {
std::stringstream(numDigit) >> result;
sum += result;
numDigit = "";
result = 0;
space = true;
}
}
std::cout << "sum = " << sum << std::endl;
}
Thanks for pointing out my mistake Pete, I've made the correction to my post.
when I was researching vectors, I noticed that size() is supposed to give the number of elements in the vector, right? So, when I found c++ does not have a string split() function built-in, I decided to make one. The problem is, vector.size() displays the same value as vector.capacity() as shown in the code:
#include <iostream>
#include <algorithm>
using namespace std;
void split(string input, char chr, vector<string> list) {
string add;
string conv;
int size = 0;
for (int i = 0; i <= input.size(); i++) {
if ((input[i] != char(chr)) && (input[i] != 0)) {
conv = input[i];
add += conv;
}
else {
cout << list.size() << endl;
if (size <= list.capacity()) {
list[size] = add;
add = "";
size++;
}
}
}
}
int main() {
vector<string> list(6);
split("test1,test2", ',', list);
for (int i = 0; i < 2; i++) {
cout << list[i] << endl;
}
}
The output is this:
6
6
<blank line>
<blank line>
whereas it SHOULD be this from my understanding:
1
2
test1
test2
Edit: if this is of any importance, I am compiling with -std=c++11
You initialize the vector with size 6, not capacity 6. It will be constructed with 6 empty elements inside and thus setting values 0 and 1 won't change that.
The reason why you see only blank lines is that you pass the vector by value instead of by reference to you split function.
#include <iostream>
#include <string>
#include <vector>
void split (const std::string& s, char sep, std::vector<std::string>& words)
{
if (s.empty()) return;
std::size_t beg = 0;
std::size_t end = s.find(sep, beg);
while (end != std::string::npos)
{
words.push_back(s.substr(beg, end - beg));
beg = end + 1;
end = s.find(sep, beg);
}
words.push_back(s.substr(beg));
}
int main() {
std::vector<std::string> words;
split("test1,test2", ',', words);
for (std::size_t i = 0; i != words.size(); ++i) {
std::cout << words[i] << std::endl;
}
return 0;
}