关于字符串表达式求值的计算,一直以来都很头疼,今天下决心研究了一天,终于完成带括号的字符串算式表达式求值:
例如,输入字符串:1-2*(3/(2-1))#,求值为-5.
特色:
1、支持double类型的输入
2、可以支持括号
3、双栈一次性完成输入和运算
4、支持混合五则运算
**输入异常,程序退出;
字符串表达式求值有多重方式,其中最常见的是中缀转后缀,然后用一个栈输入后缀表达式求值,这里我用另一种方式:利用两个栈(操作符栈、操作数栈),来存储读入的字符串表达式,然后根据输入的运算符优先级来判断是否运算,还是进行入栈操作,最终操作数的栈底就是表达式的结果,求吐槽。。。。
字符串输入以#结束,只支持合法的算术表达式,计算精度为10^(-9)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctype.h>
#include <cassert>
#include <algorithm>
#include <stack>
#include <utility>
#include <cstring>
using namespace std;
void Calculator();///字符串输入加运算判断和去括号
double operater(double left,double right,char ch);///计算函数
///判断输入字符为运算符
bool isOperator(char ch);
///栈内优先级:)、*/%、+-(、#
int isp(char ch);
///栈外优先级:(、*/%、+-、#)
int icp(char ch);
///测试打印两个栈的数据
void printstck(stack<char> stkOpr, stack<double> stkDigit);
int main()
{
while(1)
Calculator();
return 0;
}
void Calculator()
{
cout<<"please input math expression end with "<<"# ."<<endl;
cout<<"Example: 1-2*(3/(2-1))# \ninput: ";
stack<char> stkOpr;
stack<double> stkDigit;
string str = "";///存储操作数
double left,right;
char ch='#';///存储操作符
stkOpr.push(ch);///将#好入栈,放在符号栈低,作为运算结束的判断条件
bool kuohao = false;///表示符判断出栈的是否是括号
///输入补位结束符,继续输入
do
{
cin.get(ch) ;///读入字符,开始输入算术表达式
///如果是操作数,则进行入栈操作
if(isdigit(ch) || '.'==ch)
{
str.append(1,ch);
continue;
}
else if(isOperator(ch))
{
bool flag=true;///标识符判断是否连续输入运算符或者括号
if(0 == strlen(str.data()))
flag=false;
else
{
right = atof(str.c_str());///将输入操作数赋给右操作数
str = "";///清空当前操作数,准备接收新的操作数
}
///比较栈顶与栈外优先级
char tc = stkOpr.top();///拿到栈顶的操作符
while(isp(tc)>icp(ch))///栈内优先级大时,循环计算优先级较高的运算
{
flag=true;///进行运算相当于输入新的运算数
if(kuohao)///当上次栈顶为左括号时,将上次入栈的有操作数弹出栈,这里有点绕,得想想
{
stkDigit.pop();
kuohao = false;
}
printstck(stkOpr,stkDigit);///测试打印两个栈的数据
if(!stkDigit.empty())
{
///栈顶操作数出栈赋给左操作数,同时将栈顶元素出栈
left = stkDigit.top();
stkDigit.pop();
///计算当前运算并将计算结果入栈
cout<<"operater order:"<<left<<tc<<right<<endl;
right = operater(left,right,tc);
}
else
break;
if(!stkOpr.empty())///栈顶操作符出栈
{
stkOpr.pop();///计算过的操作符出栈
tc = stkOpr.top();///拿到栈顶的操作符
}
else
break;
}
///右操作数入栈
if(flag)
stkDigit.push(right);
if(isp(tc)<icp(ch))///栈内优先级小
{
///符号入栈
stkOpr.push(ch);
}
else if(isp(tc)==icp(ch))///栈内优先级小
{
if(!stkOpr.empty())///栈顶操作符出栈
{
stkOpr.pop();
kuohao = true;
}
}
}///else end
}while('#'!=ch);///while end
stkDigit.push(right);///计算结果入栈
///表达式输入结束,数字栈栈底为所求表达式的值
cout<<"result="<<stkDigit.top()<<endl;
}
///计算当前运算
double operater(double left,double right,char ch)
{
const double DEX = 1/pow(10,9);///定义运算精度
switch(ch)
{
case '+':
return left+right;
case '-':
return left-right;
case '*':
return left*right;
case '/':
if(DEX>abs(right))
{
cout<<"divide by 0! \n please try again!"<<endl;
exit(1);///异常值,程序退出
}
else
return left/right;
case '%':
if(left == (int)left && right == (int)right)
return (int)left%(int)right;
else
{
cout<<"double type connot operator '%' ! \n please try again!"<<endl;
exit(1);///异常值,程序退出
}
default:
exit(1);///异常值,程序退出
}
}
///判断输入字符为运算符
bool isOperator(char ch)
{
switch(ch)
{
case '+':
case '-':
case '*':
case '/':
case '%':
case ')':
case '(':
case '#':
return true;
default:
return false;
}
}
///栈内优先级:)、*/%、+-(、#
int isp(char ch)
{
switch(ch)
{
case '(':
return 1;
case '+':
case '-':
return 3;
case '*':
case '/':
case '%':
return 5;
case ')':
return 6;
case '#':
return 0;
default:
return -1;
}
}
///栈外优先级:(、*/%、+-、#)
int icp(char ch)
{
switch(ch)
{
case '(':
return 6;
case '+':
case '-':
return 2;
case '*':
case '/':
case '%':
return 4;
case ')':
return 1;
case '#':
return 0;
default:
return -1;
}
}
///测试打印两个栈的数据
void printstck(stack<char> stkOpr, stack<double> stkDigit)
{
stack<char> s1;
stack<double> s2;
while(!stkOpr.empty())
{
s1.push(stkOpr.top());
stkOpr.pop();
}
while(!s1.empty())
{
cout<<s1.top()<<" ";
stkOpr.push(s1.top());
s1.pop();
}
cout<<endl;
while(!stkDigit.empty())
{
s2.push(stkDigit.top());
stkDigit.pop();
}
cout<<" ";
while(!s2.empty())
{
cout<<s2.top()<<" ";
stkDigit.push(s2.top());
s2.pop();
}
cout<<endl;
}
作者:yanxiaocheng 出处:https://blog.csdn.net/u014474985