當我們遇到很複雜的四則運算,怎麼通過編程實現呢?例如: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.遞歸退出的條件是什麼?而上述複雜的四則運算遞歸終止條件:內部表達式不再有任何括號。
遞歸不再侷限於函數本身來調用自己,也可以函數本身通過間接方式來調用到自己。