简单表达式的求值,在《数据结构》教课书上有明确的阐述。
先处理只涉及四则运算的情况。
再添加小括号的情况。
然后处理表达式中包含实数的情况。
最后处理表达式中包含空格的情况。
1设立两个栈,运算符栈和数字栈。
2遍历表达式,解析出里面的数字和运算符。
3数字部分直接压栈,运算符部分视优先级情况而定。
4遍历完毕,数字栈中剩余的那一个数字时,为运算结果。
只涉及四则运算的使用,数字全为整数。
代码的主要逻辑在main函数中。
ch2num函数完成运算符到数字的映射。
规则为:‘#’---0,‘+’---1,‘-’---2,‘*’---3,‘/’---4。
compare二维数组记录运算符之间的优先级。
compare[i][j]=1,表示i比j优先级高;compare[i][j]=0,表示i的优先级不高于j。
Operator_2
函数完成四则运算。简单表达式的求值,在《数据结构》教课书上有明确的阐述。先处理只涉及四则运算的情况。再添加小括号的情况。然后处理表达式中包含实数的情况。最后处理表达式中包含空格的情况。对于只涉及加减乘除的表达式,1设立两个栈,运算符栈和数字栈。2遍历表达式,解析出里面的数字和运算符。3数字部分直接压栈,运算符部分视优先级情况而定。4遍历完毕,数字栈中剩余的那一个数字时,为运算结果。只涉及四则运算的使用,数字全为整数。代码的主要逻辑在main函数中。ch2num函数完成运算符到数字的映射。规则为:‘#’---0,‘+’---1,‘-’---2,‘*’---3,‘/’---4。compare二维数组记录运算符之间的优先级。compare[i][j]=1,表示i比j优先级高;compare[i][j]=0,表示i的优先级不高于j。operator_2函数完成四则运算。
#include<stdio.h>#include<stack>#include<string.h>using std::stack;int ch2num(char ch) { int num(-1); switch (ch) { case '#':num = 0; break; case '+':num = 1; break; case '-':num = 2; break; case '*':num = 3; break; case '/':num = 4; break; }//switch return num;}//ch2numdouble operator_2(double num1, double num2, char ch) { double num(0.0); switch (ch) { case '+':num = num2 + num1; break; case '-':num = num2 - num1; break; case '*':num = num2*num1; break; case '/':num = num2 / num1; break; }//switch return num;}//operator_2int compare[5][5] = { { 0 },{ 1 },{ 1 },{ 1,1,1 },{ 1,1,1 } };int main() { freopen("in.txt", "r", stdin); char str[250]; stack<double> S_num; stack<char> S_ch; while (gets_s(str)) { while (!S_ch.empty())S_ch.pop(); S_ch.push('#'); while (!S_num.empty())S_num.pop(); int tnum(0); for (int i(0); str[i] != '/0'; ++i) { //累加数字 if ('0' <= str[i] && str[i] <= '9') { tnum *= 10; tnum += str[i] - 48; } //遇到运算符,先把数字tnum压入S_num,然后视优先级情况而定下面的操作。 else { S_num.push(tnum); tnum = 0; if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]); //运算符str[i]的优先级较高,直接压入。 else { //将S_ch.top()弹出,一直到存在某个S_ch.top()的优先级低于str[i]。 //由于S_ch栈底部有个'#',所以不用担心S_ch弹空。 while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) { char ch = S_ch.top(); S_ch.pop(); double num1 = S_num.top(); S_num.pop(); double num2 = S_num.top(); S_num.pop(); S_num.push(operator_2(num1, num2, ch)); }//while S_ch.push(str[i]); }//if else }//if else }//for i S_num.push(tnum); char ch('/0'); //依次计算完所有的运算符 while ((ch = S_ch.top()) != '#') { S_ch.pop(); double num1 = S_num.top(); S_num.pop(); double num2 = S_num.top(); S_num.pop(); S_num.push(operator_2(num1, num2, ch)); }//while PRintf("%.2f/n", S_num.top()); }//while return 0;}//main细节:gets_s函数,gets函数,S_ch栈底预先放置‘#’,作为优先级最低的运算符,功能上类似于“哨兵”。
Freopen(“in.txt”,”r”,stdin)是重定向语句,可以在相应位置安排in.txt文件编辑测试用例,也可以去掉改行代码,自己在控制台输入测试用例。
虽然表达式中只有整数,但是S_num里面存放的元素是double。
Compare的维度明显偏大,可以设置成compare[5][3]。
二、添加小括号。
逻辑上的主要改变就是‘(’,‘)’括号分开处理。
Str[i]为‘(’,则直接压入S_ch;如果栈顶为‘(’,任何运算符的优先级都比它大。
Str[i]为‘)’,视情况脱去跟它相匹配的那个左括号,参考main里的代码。
优先级部分参考compare[5][6]二维数组。
并且完美支持了正数和负数的处理。
比如:
把这(-2)看作是(0-2)的运算
(+2)看作是(0+2)的运算
(2)是在有个puts("here")输出那处理的,先从S_num里pop出来,稍后再压进去,用这种伎俩来统一流程。
-5+3-5这种式子的,第一个-5是看做0-5来处理的。
#include<stdio.h>
#include<stack>
using std::stack;
int ch2num(constchar&ch) {
intnum(-1);
switch(ch){
case'#':num = 0; break;
case'+':num = 1; break;
case'-':num = 2; break;
case'*':num = 3; break;
case'/':num = 4; break;
case'(':num = 5; break;
case')':num = 6; break;
}//switch
returnnum;
}//ch2num
int operator_2(constint&num1,constint&num2,constchar&ch) {
intnum(-1);
switch(ch){
case'+':num = num2 +num1;break;
case'-':num = num2 -num1;break;
case'*':num = num2 *num1;break;
case'/':num = num2 /num1;break;
}//switch
returnnum;
}//operator_2
int compare[5][6] = { { 0 },{ 1, 0, 0,0, 0, 1 },{ 1, 0, 0, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 } };
int main() {
freopen("in.txt","r",stdin);
charstr[250];
stack<int>S_num;
stack<char>S_ch;
while(gets_s(str)) {
while(!S_ch.empty())S_ch.pop();
S_ch.push('#');
while(!S_num.empty())S_num.pop();
inttnum(0);
for(inti(0); str[i] != '/0';) {
if('0' <= str[i] && str[i] <= '9') {
tnum*= 10;
tnum+= str[i] - '0';
++i;
}
elseif(str[i] == '(') {
S_ch.push('(');
++i;
}
elseif(str[i] == ')') {
S_num.push(tnum);
//dealutil (
charch = S_ch.top();
if(ch !='(') {//justone operator,if this step is ignored,so...
S_ch.pop();
intnum1 = S_num.top();
S_num.pop();
intnum2 = S_num.top();
S_num.pop();
tnum= operator_2(num1, num2, ch);
}
else{
//puts("here");
tnum= S_num.top();
S_num.pop();
}//ifelse
S_ch.pop();
++i;
}
else{
S_num.push(tnum);
tnum= 0;
if(compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);
else{
while(compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {
charch = S_ch.top();
S_ch.pop();
intnum1 = S_num.top();
S_num.pop();
intnum2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1,num2, ch));
}//while
S_ch.push(str[i]);
}//ifelse
++i;
}//ifelse if else if else
}//fori
S_num.push(tnum);
charch('/0');
while((ch = S_ch.top()) !='#') {
S_ch.pop();
intnum1 = S_num.top();
S_num.pop();
intnum2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1,num2, ch));
}//while
printf("%d/n", S_num.top());
}//while
return0;
}//main
三、添加实数的处理
数字累加的部分发生变化,tnum定义为double型,weight_del定义为小数部分的权重。
int main() {
freopen("in.txt","r",stdin);
charstr[250];
stack<double>S_num;
stack<char>S_ch;
while(gets_s(str)) {
while(!S_ch.empty())S_ch.pop();
S_ch.push('#');
while(!S_num.empty())S_num.pop();
doubletnum(0.0);
doubleweight_del(0.0);
for(inti(0); str[i] != '/0'; ++i) {
if('0' <= str[i] && str[i] <= '9' || str[i] =='.'){
if('0' <= str[i] && str[i] <= '9') {
if(weight_del == 0.0) {
tnum*= 10;
tnum+= str[i] - '0';
}
else{
tnum+= weight_del*(str[i] - '0');
weight_del*= 0.1;
}//ifelse
}
elseif(str[i] == '.')weight_del = 0.1;
}
elseif(str[i] == '(')S_ch.push('(');
elseif(str[i] == ')') {
S_num.push(tnum);
tnum= 0.0;
weight_del= 0.0;
//dealutil (
charch(S_ch.top());
if(ch != '(') {//justone operator,if this step is ignored,so...
S_ch.pop();
doublenum1 = S_num.top();
S_num.pop();
doublenum2 = S_num.top();
S_num.pop();
tnum= operator_2(num1, num2, ch);
}
else{
//puts("here");
tnum= S_num.top();
S_num.pop();
}//ifelse
S_ch.pop();//pop(
}
else{
S_num.push(tnum);
tnum= 0.0;
weight_del= 0.0;
if(compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);
else{
while(compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {
charch = S_ch.top();
S_ch.pop();
doublenum1 = S_num.top();
S_num.pop();
doublenum2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1,num2, ch));
}//while
S_ch.push(str[i]);
}//ifelse
}//ifelse if else if else
}//fori
S_num.push(tnum);
charch('/0');
while ((ch =S_ch.top()) !='#') {
S_ch.pop();
doublenum1 = S_num.top();
S_num.pop();
doublenum2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1,num2, ch));
}//while
printf("%f/n", S_num.top());
}//while
return0;
}//main
四、剔除空格
如果表达式中含有多余空格的情况,需要预处理一下输入字符串str,就是剔除里面的空格,编写函数如下。
void replace_space(char*str){
inti(-1), j(-1);
for(i = 0, j = 0;str[j] !='/0';j++)if (str[j]!=' ')
str[i++]=str[j];
str[i]='/0';
return;
}//replace_space
放置在main函数中的如下位置
while (gets_s(str)){
replace_space(str);
。。。
}//while
五、封装calculator类
class Calculator {private: double result; string input; stack<double> S_num; stack<char> S_ch; const int compare[5][6] = { { 0 },{ 1, 0, 0, 0, 0, 1 },{ 1, 0, 0, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 } }; int ch2num(const char &ch) { int num(-1); switch (ch) { case '#':num = 0; break; case '+':num = 1; break; case '-':num = 2; break; case '*':num = 3; break; case '/':num = 4; break; case '(':num = 5; break; case ')':num = 6; break; }//switch return num; }//ch2num double operator_2(const double &num1, const double &num2, const char &ch) { double num(-1); switch (ch) { case '+':num = num2 + num1; break; case '-':num = num2 - num1; break; case '*':num = num2 * num1; break; case '/':num = num2 / num1; break; }//switch return num; }//operator_2 void replace_space(string &str) { int i(-1), j(-1); for (i = 0, j = 0; str[j] != '/0'; j++) if (str[j] != ' ') str[i++] = str[j]; str[i] = '/0'; return; }//replace_space void calc() { string str(input); replace_space(str); if (str == "")return; while (!S_ch.empty())S_ch.pop(); S_ch.push('#'); while (!S_num.empty())S_num.pop(); double tnum(0.0); double weight_del(0.0); for (int i(0); str[i] != '/0'; ++i) { if ('0' <= str[i] && str[i] <= '9' || str[i] == '.') { if ('0' <= str[i] && str[i] <= '9') { if (weight_del == 0.0) { tnum *= 10; tnum += str[i] - '0'; } else { tnum += weight_del*(str[i] - '0'); weight_del *= 0.1; }//if else } else if (str[i] == '.')weight_del = 0.1; } else if (str[i] == '(')S_ch.push('('); else if (str[i] == ')') { S_num.push(tnum); tnum = 0.0; weight_del = 0.0; char ch(S_ch.top()); if (ch != '(') { S_ch.pop(); double num1 = S_num.top(); S_num.pop(); double num2 = S_num.top(); S_num.pop(); tnum = operator_2(num1, num2, ch); } else { tnum = S_num.top(); S_num.pop(); }//if else S_ch.pop(); } else { S_num.push(tnum); tnum = 0.0; weight_del = 0.0; if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]); else { while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) { char ch = S_ch.top(); S_ch.pop(); double num1 = S_num.top(); S_num.pop(); double num2 = S_num.top(); S_num.pop(); S_num.push(operator_2(num1, num2, ch)); }//while S_ch.push(str[i]); }//if else }//if else if else if else }//for i S_num.push(tnum); char ch('/0'); while ((ch = S_ch.top()) != '#') { S_ch.pop(); double num1 = S_num.top(); S_num.pop(); double num2 = S_num.top(); S_num.pop(); S_num.push(operator_2(num1, num2, ch)); }//while result = S_num.top(); return; }//calcpublic: Calculator(string input = "") { this->input = input; result = 0.0; return; }//Calculator void inputStr(string input) { this->input = input; result = 0.0; calc(); return; }//inputStr double getResult() { return result; }//getResult};本文没有处理非法表达式的部分。
新闻热点
疑难解答