当我们遇到很复杂的四则运算,怎么通过编程实现呢?例如:34*(23-(1+23)*4-324)*(23-32*(23-324)/(34+34))/(43-45*343)
此字符串输入,求取表达式的结果是多少呢?自己头脑是什么思路?回想以前的数学的证明题,都是从最简单的思考开始,此表达式字符串分析也不例外。
只考虑加减法
加减法是同级运算,故只需字符串向后移动即可,实现比较简单。最关键的是在于获取操作数。初始直接获取操作数getNum
,后续遇到+,-
符号的时候,都需要调用getNum
来获取操作数。故两个操作数被获取,完成加减操作,完成的结果又是第一个操作数,重复此过程,从而得到最后的结果。
# include<iostream>
using namespace std;
void removeSpace(char *str){
char *p1=str,*p2=str;
while ((*p1=*p2++)) {
if (*p1 != ' ') {
p1++;
}
}
}
bool isNumber(const char ch){
return '0'<=ch && ch<='9';
}
double getNum(char *str,int *index){
double v=0.0;
while(isNumber(*(str+*index))){
v=v*10+*(str+*index)-'0';
(*index)++;
}
if (*(str+*index)!='.'){
return v;
}
double decimal=1.0;
while(isNumber(*(str+(++*index)))){
decimal/=10;
v+=decimal*(*(str+*index)-'0');
}
return v;
}
double lowerCount(char *str,int *index){
double v1=getNum(str,index);
while(*(str+*index)){
switch (*(str+(*index)++)){
case '+':
v1+=getNum(str,index);
break;
case '-':
v1-=getNum(str,index);
break;
case '\0':
return v1;
}
}
return v1;
}
int main(int argc, char **argv){
char str[100]={"2+10+7+10"};
removeSpace(str);
int index=0;
cout<<lowerCount(str,&index)<<endl;
}
加减法基础上增加乘除法
由于加减法的优先级比乘除法低,故加减法的操作数获取需要调用乘除法的结果。而乘除法本身是同级的,故乘除法的操作数可以通过getNum
来进行获取(重复上述加减法过程),直到遇到非*,/
字符返回结果作为加减法的操作数。
# include<iostream>
using namespace std;
void removeSpace(char *str){
char *p1=str,*p2=str;
while ((*p1=*p2++)) {
if (*p1 != ' ') {
p1++;
}
}
}
bool isNumber(const char ch){
return '0'<=ch && ch<='9';
}
double getNum(char *str,int *index){
double v=0.0;
while(isNumber(*(str+*index))){
v=v*10+*(str+*index)-'0';
(*index)++;
}
if (*(str+*index)!='.'){
return v;
}
double decimal=1.0;
while(isNumber(*(str+(++*index)))){
decimal/=10;
v+=decimal*(*(str+*index)-'0');
}
return v;
}
double moreCount(char *str,int *index){
double v1=getNum(str,index);
while(*(str+*index)){
switch (*(str+*index)){
case '*':
(*index)++;
v1*=getNum(str,index);
break;
case '/':
(*index)++;
v1/=getNum(str,index);
break;
default:
return v1;
}
}
return v1;
}
double lowerCount(char *str,int *index){
double v1=moreCount(str,index);
while(*(str+*index)){
switch (*(str+(*index)++)){
case '+':
v1+=moreCount(str,index);
break;
case '-':
v1-=moreCount(str,index);
break;
case '\0':
return v1;
}
}
return v1;
}
int main(int argc, char **argv){
char str[100]={"2*10+7*10+4*5+2*3"};
removeSpace(str);
int index=0;
cout<<lowerCount(str,&index)<<endl;
}
乘除法基础上加括号
括号运算的优先级高于乘除法,而括号内的运算本质又是+,-,*,/,()
构成,因此乘除法通过getNum
获取操作数的时候,需要考虑括号表达式,若有括号,则把括号的结果作为乘除法的操作数;若无括号,直接读取数字作为操作数。而括号表达式内的子串又是一个复杂的+,-,*,/,()
表达式构成,因此计算括号内的结果我们可以递归调用加减法计算函数,从而最终能够完成括号表达式的结果。
# include<iostream>
using namespace std;
void removeSpace(char *str){
char *p1=str,*p2=str;
while ((*p1=*p2++)) {
if (*p1 != ' ') {
p1++;
}
}
}
bool isNumber(const char ch){
return '0'<=ch && ch<='9';
}
char * bracket(char* str, int* index){
int num=1,start=++(*index);
while(*(str+*index)){
if (*(str+*index)=='('){
num++;
(*index)++;
continue;
}
if (*(str+*index)==')'){
if (--num==0){
char * p=(char*)malloc(sizeof(char)*(*index-start+1));
memcpy(p,str+start,*index-start);
p[*index-start+1]='\0';
(*index)++;
return p;
}
}
(*index)++;
}
return nullptr;
}
double lowerCount(char *str,int *index);
double getNum(char *str,int *index){
double v=0.0;
if (*(str+*index)=='('){
char *substr=bracket(str,index);
int pindex=0;
double v1=lowerCount(substr,&pindex);
free(substr);
return v1;
}
while(isNumber(*(str+*index))){
v=v*10+*(str+*index)-'0';
(*index)++;
}
if (*(str+*index)!='.'){
return v;
}
double decimal=1.0;
while(isNumber(*(str+(++*index)))){
decimal/=10;
v+=decimal*(*(str+*index)-'0');
}
return v;
}
double moreCount(char *str,int *index){
double v1=getNum(str,index);
while(*(str+*index)){
switch (*(str+*index)){
case '*':
(*index)++;
v1*=getNum(str,index);
break;
case '/':
(*index)++;
v1/=getNum(str,index);
break;
default:
return v1;
}
}
return v1;
}
double lowerCount(char *str,int *index){
double v1=moreCount(str,index);
while(*(str+*index)){
switch (*(str+(*index)++)){
case '+':
v1+=moreCount(str,index);
break;
case '-':
v1-=moreCount(str,index);
break;
case '\0':
return v1;
}
}
return v1;
}
int main(int argc, char **argv){
char str[100]={"2*(10+7*10)+4*5+2*3"};
removeSpace(str);
int index=0;
cout<<lowerCount(str,&index)<<endl;
}
总结
一个复杂的问题,往往从最简单的开始进行考虑,一步一步往里面添加条件,从而问题能够有效的解决。而递归解决问题也需要这样建立问题解决方法。递归抓住两点:1.怎样方式递归的?2.递归退出的条件是什么?而上述复杂的四则运算递归终止条件:内部表达式不再有任何括号。
递归不再局限于函数本身来调用自己,也可以函数本身通过间接方式来调用到自己。