四則運算java實現

實現四則運算一般都是利用自動機理論,對字符逐個讀取,然後判斷應處的狀態,最後將自動機優化實現程序。
只是突然想起有另一種計算方式,不知是否有前輩已經寫出,只是怕自己會突然忘記,因此記錄下來,供以後使用。

對於一個簡單的加減法運算來說(拋去有正數或負數的存在,因爲負號與減號容易混淆),符號總是比數據少一個,例如

/*對於一個四則元算字符串:A+B-C 來說,若是以符號爲分隔將數和運算符分開,以向量來存儲,那麼結果爲:*/
number:A B C
operator:+ -

此時怎麼做應該很清楚了吧,對向量operator取第一個成員,此時得到了一個“+”號,那麼只要取number中的兩個數,然後讓兩個數相加(假如說得到了D,此時要根據運算符號來操作兩個數),放入number第一個成員位置,再移除operator第一個成員,移除number第二個成員,例如:

number.setElementAt(number.firstElement()+number.get(1),0);
number.remove(1);
operator.remove(0);
/*此時兩個向量中剩下的內容是什麼:
number:D C
operator:-

看到了吧,繼續上次的運算,直到operator中爲空,此時number中必定還剩下一個成員,那就是最終的結果,下面貼出完整步驟:

while(!operator.isEmpty()){
    char ch=operator.firstElement();
    if(ch=='+'){
        number.setElementAt(number.firstElement()+number.get(1),0);
    }else if(ch=='-'){
        number.setElementAt(number.firstElement()-number.get(1),0);
    }
    number.remove(1);
    operator.remove(0);
}
return number.firstElement().toString();

看到這大家估計會嗤之以鼻,說這玩意早幾百年都懂了,還寫這幹啥,當然,沒有哪個運算只有加減法,還不能帶符號的,接下來就進行加減法的進階——乘除法。
別笑!
容我先貼出完整的程序來,然後再分析:

protected static String account_second(Vector<Float> number,Vector<Character> operator){
/*對於靜態方法account_second來說,呃,這個函數名字很讓我糾結,不過不想去改代碼了,number代表字符串分割後數的集合,operator相當於分割後操作數的集合*/
    try {
        int k=0;
        while(operator.size()>k){
            char ch=operator.get(k);
            if(operator.get(k)=='*'){
                number.setElementAt(number.get(k) * number.get(k+1), k);
            }
            else if(ch=='%'){
                number.setElementAt(number.get(k)%number.get(k+1),k);
            }
            else if(ch=='/'){
                number.setElementAt(number.get(k)/number.get(k+1),k);
            }
            //碰到“高級”運算直接操作,此時都是二目運算符,因此不會有問題。
            else if(ch=='+'||ch=='-') {
                k++;
                continue;
            }
            //碰到“低級”運算符要讓位,這裏只進行高級運算。
            number.remove(k+1);
            operator.remove(k);
        }
        while(!operator.isEmpty()){
            char ch=operator.firstElement();
            if(ch=='+'){
                number.setElementAt(number.firstElement()+number.get(1),0);
            }else if(ch=='-'){
                number.setElementAt(number.firstElement()-number.get(1),0);
            }
            number.remove(1);
            operator.remove(0);
        }
        return number.firstElement().toString();
        //這部分不解釋,就是之前貼過的代碼。
    } catch(Exception e){
        return "input error";
    }
    //我非常認真的提醒大家,try catch是精髓,它可以保證:
    //咳,保證程序不小心有問題也不會檢查不出來。
}

看到這你估計就明白爲什麼我先貼代碼了,沒錯,按照四則運算的規矩,乘除先行,這裏就是先進行了乘除法的運算,直到operator中沒有乘除取模爲止,若是中間遇到加減符號,直接隔過就行。怎麼樣,簡單吧。
或許對此你仍然不屑一顧,沒有括號的四則運算能叫運算麼?
對,你說的對,這程序若到此爲止,我也不好意思貼出來了,簡直是打我老師的臉。下面進行乘除進階——括號運算。

其實這部分也沒有什麼大問題,只是我思維偏向於混亂,因此這部分的代碼很垃圾,不過總算把功能實現了,如果誰有更爲精準簡潔的代碼,請務必不要告訴我,我怕打臉。
好了,下面還是貼代碼:

public static String account(String string) {

    boolean flag=true;
    try {
        Vector<Float> number=new Vector<Float>();
        Vector<Character> operator=new Vector<Character>();
        //定義存儲運算符和操作數的向量。
        String strings[] = string.split("\\+|-|\\*|%|/|\\(|\\)");/*此處是將四則運算字符串以操作符爲界限進行分割,切記加號乘號以及括號匹配時候是需要轉義的,具體內容請自學正則表達式。“+,-,*,/,%,(,)”*/
        for (String i : strings) {
            if(!i.equals("")) {
                number.add(Float.parseFloat(i));
            }
        }
        //將分割後得到的字符串轉化爲float類型存在number裏。
        char chars[] = string.toCharArray();
        int num[]=new int[number.size()];
        int k=0;
        for (Character i : chars) {
            if (i == '+' || i == '-' || i == '*' || i == '/' || i == '%') {
                operator.add(i);
                k++;
            }else if(i=='('){
                num[k]++;
            }else if(i==')'){
                num[k]--;
            }
        }
        /*這部分估計你傻眼了吧,其實很簡單,首先對字符串數組化得到操作符,這過程中肯定會碰到括號,因此新建一個與number對應的數組num,裏面記錄括號的位置,碰到一個左括號“(”,就讓對應number所在位置的num加一,碰到一個“)”,就讓對應number位置的num減一,因爲括號的匹配性,查找完之後,num數組中所有數加起來應該還是零。*/
        /*不知你發現沒有,此時此刻operator中數據個數還是比number中數據個數少一,一定要記住,這纔是這種算法存在的基礎,要不然天曉得自己應該操作哪個數*/
        flag=true;
        while(flag){
            for(int i=0;i<num.length;i++){
                if(num[i]<0){
                    num[i]+=1;//左括號值爲1,右括號值爲-1;

                    flag=!flag;
                    for(int j=i-1;j>=0;j--){
                        if(num[j]>0){
                            num[j]-=1;
                            num[j]=num[j]+num[i];
                            if(i+1!=num.length){
                                for(int t=i+1;t<num.length;t++){
                                    num[t-(i-j)]=num[t];
                                }
                            }
                            for(int t=num.length-(i-j);t<num.length;t++){
                                num[t]=0;
                            }//將數組中括號匹配到位

                            Vector<Float> new_number=new Vector<Float>();
                            Vector<Character> new_operator=new Vector<Character>();
                            for(int p=j;p<=i-1;p++){
                                new_number.add(number.get(p));
                                new_operator.add(operator.get(p));
                            }
                            new_number.add(number.get(i));

                            String str=account_second(new_number,new_operator);
                            if(!str.equals("input error")){
                                number.setElementAt(Float.parseFloat(str),i);
                            }
                            else{
                                return "input error";
                            }
                            //將括號中數與符號單獨提出,新建對應的向量,然後利用second-account求出值,再將新值
                            //放入原來向量,直到沒有括號爲止。

                            for(int m=j;m<i;i--){
                                number.remove(j);
                                operator.remove(j);
                            }
                            j=-1;i=num.length;
                        }
                    }
                }
            }
            flag=!flag;
        }
        return account_second(number,operator);
    } catch (Exception e) {
        return "error";
    }
}
後面有很長一部分沒有註釋,實在是我的算法太噁心,我自己都不好意思說明白,我只說一下大致要實現的功能:
講解過的部分經過操作應該會得到三個集合,operator,numbernum;
對於一個運算式  (7+(5-3))*2  來說,這三部分內容分別如下:
number7    5    3     2
num1    1    -2    0
operator:+  -   *
就是這樣,括號的位置記錄在與之接近的操作數上,且不會有單個括號同時接近兩個操作數。
根據四則運算法則,有括號先計算括號裏面的內容,有多個括號呢?那就應該先從左到右查找第一個右括號“)”,然後從第一個右括號開始,向左查找第一個左括號“(”,裏面的部分就是你要先計算的。
括號裏面的內容肯定不含括號了,那就調用使用之前寫的計算乘除加減的方法,將得到的數值寫入number中,然後將括號位置對應的num中數字變化,
還要移除已經使用過的operator中的操作符,移除運算過的number中的操作數,直到num中數字全爲零,最後會剩下沒有括號干擾的number和operator,這下就好辦了吧。

好了以上就是四則運算的java實現,是不是有種噁心的感覺?沒關係,我們接着看,正數和負數的問題還沒解決呢。
好吧,其實最後的問題很好解決,在開始分割字符串之前檢查一下就好了,如果發現有減號出現並且該減號左端不是數字,那麼~~~那麼就在減號前面加個零“0”好了,不要嘗試去直接修改operator中對應的值,那樣會很蠢。這樣得到的字符串不就很規範了麼。自己寫的實現代碼如下:

    public static String addChar(String string,int i,boolean b,String str){
        if(b){
            String frontPart = string.substring(0, i);
            String backPart = string.substring(i);
            string = frontPart + str + backPart;
        }else{
            String frontPart=string.substring(0,i+1);
            String backPart = string.substring(i+1);
            string=frontPart+str+backPart;
        }
        return string;
    }

    while(flag) {
        flag=!flag;
        string=string.replace(" ","");
        char ch[] = string.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            if(ch[i] == '-' || ch[i] == '+') {
                if (i == 0 || (i != 0 && ch[i - 1] == '(')) {
                    string=addChar(string,i,true,"0");
                    flag =!flag;
                    break;
                }
                if(i==ch.length-1||(i!=ch.length-1&&ch[i+1]==')')){
                    string=addChar(string,i,false,"0");
                    flag=!flag;
                    break;
                }
            }
            if(i!=0&&ch[i]=='('&&'0'<=ch[i-1]&&ch[i-1]<='9'){
                string=addChar(string,i,true,"*");
                flag=!flag;
                break;
            }
            if(i!=ch.length-1&&ch[i]==')'&&'0'<=ch[i+1]&&ch[i+1]<='9'){
                string=addChar(string,i,false,"*");
                flag=!flag;
                break;
            }
        }
    }

這段代碼不單單是解決了負號正號存在的問題,還可以去除字符串空格,以及很多的錯誤輸入問題,如”1+3+”,這明顯是輸入錯誤,而我們可以將其處理,比如變成“1+3+0”,或者“1+3”;還有省略乘號的問題,如“(2+7)4”,我們將其變爲“(2+7)*4”,這樣是不是就人性化多了呢?
當然,這種想法還可以繼續延伸,比如階乘符號怎麼算,次方怎麼算,根號怎麼算,這些都可以根據運算優先級來得到解決。

好了,終於到結尾了,想吐的同學可以吐了,這是我之前自己鼓搗安卓計算器的時候整的,最後時候計算器也能用,因此代碼應該沒問題,但不排除我粘貼複製出手抖出錯,整個計算過程完整代碼附上:


import java.util.*;
/**
 * Created by wang on 2015/10/6.
 */
public class Account{
    public static String addChar(String string,int i,boolean b,String str){
        if(b){
            String frontPart = string.substring(0, i);
            String backPart = string.substring(i);
            string = frontPart + str + backPart;
        }else{
            String frontPart=string.substring(0,i+1);
            String backPart = string.substring(i+1);
            string=frontPart+str+backPart;
        }
        return string;
    }
public static String account(String string) {

    boolean flag=true;
    while(flag) {
        flag=!flag;
        string=string.replace(" ","");
        char ch[] = string.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            if(ch[i] == '-' || ch[i] == '+') {
                if (i == 0 || (i != 0 && ch[i - 1] == '(')) {
                    string=addChar(string,i,true,"0");
                    flag =!flag;
                    break;
                }
                if(i==ch.length-1||(i!=ch.length-1&&ch[i+1]==')')){
                    string=addChar(string,i,false,"0");
                    flag=!flag;
                    break;
                }
            }
            if(i!=0&&ch[i]=='('&&'0'<=ch[i-1]&&ch[i-1]<='9'){
                string=addChar(string,i,true,"*");
                flag=!flag;
                break;
            }
            if(i!=ch.length-1&&ch[i]==')'&&'0'<=ch[i+1]&&ch[i+1]<='9'){
                string=addChar(string,i,false,"*");
                flag=!flag;
                break;
            }
        }
    }
    try {
        Vector<Float> number=new Vector<Float>();
        Vector<Character> operator=new Vector<Character>();
        String strings[] = string.split("\\+|-|\\*|%|/|c|s|\\(|\\)");
        for (String i : strings) {
            if(!i.equals("")) {
                number.add(Float.parseFloat(i));
            }
        }
        char chars[] = string.toCharArray();
        int num[]=new int[number.size()];
        int k=0;
        for (Character i : chars) {
            if (i == '+' || i == '-' || i == '*' || i == '/' || i == '%') {
                operator.add(i);
                k++;
            }else if(i=='('){
                num[k]++;
            }else if(i==')'){
                num[k]--;
            }
        }

        flag=true;
        while(flag){
            for(int i=0;i<num.length;i++){
                if(num[i]<0){
                    num[i]+=1;//左括號值爲1,右括號值爲-1;

                    flag=!flag;
                    for(int j=i-1;j>=0;j--){
                        if(num[j]>0){
                            num[j]-=1;

                            num[j]=num[j]+num[i];
                            if(i+1!=num.length){
                                for(int t=i+1;t<num.length;t++){
                                    num[t-(i-j)]=num[t];
                                }
                            }
                            for(int t=num.length-(i-j);t<num.length;t++){
                                num[t]=0;
                            }//將數組中括號匹配到位

                            Vector<Float> new_number=new Vector<Float>();
                            Vector<Character> new_operator=new Vector<Character>();
                            for(int p=j;p<=i-1;p++){
                                new_number.add(number.get(p));
                                new_operator.add(operator.get(p));
                            }
                            new_number.add(number.get(i));

                            String str=account_second(new_number,new_operator);
                            if(!str.equals("input error")){
                                number.setElementAt(Float.parseFloat(str),i);
                            }
                            else{
                                return "input error";
                            }
                            //將括號中數與符號單獨提出,新建對應的向量,然後利用second-account求出值,再將新值
                            //放入原來向量,直到沒有括號爲止。

                            for(int m=j;m<i;i--){
                                number.remove(j);
                                operator.remove(j);
                            }
                            j=-1;i=num.length;
                        }
                    }
                }
            }
            flag=!flag;
        }
        return account_second(number,operator);
    } catch (Exception e) {
        return "error";
    }
}

    protected static String account_second(Vector<Float> number,Vector<Character> operator){
        try {
            int k=0;
            while(operator.size()>k){
                char ch=operator.get(k);
                if(operator.get(k)=='*'){
                    number.setElementAt(number.get(k) * number.get(k+1), k);
                }
                else if(ch=='%'){
                    number.setElementAt(number.get(k)%number.get(k+1),k);
                }
                else if(ch=='/'){
                    number.setElementAt(number.get(k)/number.get(k+1),k);
                }
                else if(ch=='+'||ch=='-') {
                    k++;
                    continue;
                }
                number.remove(k+1);
                operator.remove(k);
            }
            while(!operator.isEmpty()){
                char ch=operator.firstElement();
                if(ch=='+'){
                    number.setElementAt(number.firstElement()+number.get(1),0);
                }else if(ch=='-'){
                    number.setElementAt(number.firstElement()-number.get(1),0);
                }
                number.remove(1);
                operator.remove(0);
            }
            return number.firstElement().toString();
        } catch(Exception e){
            return "input error";
        }
    }
}


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