複雜四則運算程序實現

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章