java根據Stack棧實現公式解析和自定義函數(二)

今天在準備繼續拓展時發現了個問題,加減乘除的參數如果前面的值大於兩位數後面的值大於一位時結果不正確甚至可能會報錯,排查後發現是我在定義循環完畢的 i 位數固定了數值不是動態加載造成的問題

修改成根據結果長度的位數加減i:

執行結果(多位數也沒有問題了):

--------------------------------------------------------------- 我是間隔線 ----------------------------------------------------------

--------------------------------------------------------------- 我是間隔線 ----------------------------------------------------------

看完子楓妹妹繼續來敲代碼,接下來要來解決加減乘除括號或者函數的問題。

前綴示例:1+max(1,2,3)     1+(1+1) 

後綴示例: max(1,2,3)+1   

解決思路(後綴):

先來說後綴的計算,因爲當字符循環到符號這時,在之前的括號內的都已經計算完成存在了棧裏(看前面的源代碼右括號那部分),所以我們在驗證加減乘除符號前面的值是括號時直接從棧內取出值就是括號內的結果值,然後該怎麼執行怎麼執行。

後綴計算核心部分:

源代碼:

package com.example.demo.java;

import java.time.Month;
import java.util.Scanner;
import java.util.Stack;

/**
 * @author Anzepeng
 * @title: JavaCalculate
 * @projectName demo
 * @description: TODO
 * @date 2020/6/4 0004上午 9:06
 */
public class JavaCalculate {
    public static Stack<String> operation = new Stack<String>();  //存放運算符
    public static Stack<Character> bracket = new Stack<Character>(); //存放左括號
    public static Stack<Integer> number = new Stack<Integer>(); //存放運算參數
    public static Stack<Integer> count = new Stack<Integer>(); //存放運算符參數個數

    public int add(int[] N) {
        int i = 0;
        for (int f = 0; f < N.length; f++){
            i += N[f];
        }
        return i;
    }

    public int max(int[] N) {
        int i = 0;
        for (int f = 0; f < N.length; f++){
            if (f == 0){
                i = N[f];
            }else{
                if (i<N[f]){
                    i = N[f];
                }
            }
        }
        return i;
    }

    public int min(int[] N) {
        int i = 0;
        for (int f = 0; f < N.length; f++){
            if (f == 0){
                i = N[f];
            }else{
                if (i>N[f]){
                    i = N[f];
                }
            }
        }
        return i;
    }

    public int doubleMe(int[] N) {
        return 2 * N[0];
    }

    public boolean judgeChar(char s) {
        if(s >= 'a' && s <= 'z' || s >= 'A' && s <= 'Z')
            return true;
        return false;
    }

    public boolean judgeNumber(char s) {
        if(s >= '0' && s <= '9')
            return true;
        return false;
    }

    public void getResult(String A) {
        String temp = "";
        for(int i = 0;i < A.length();i++) {
            // 驗證是否在a和z之間
            if(judgeChar(A.charAt(i))) {
                temp = temp + A.charAt(i);
                i = i + 1;
                while(judgeChar(A.charAt(i))) {
                    temp = temp + A.charAt(i);
                    i++;
                }
                i = i - 1;
                operation.push(temp);
                count.push(0);  //剛尋找到一個運算符,並初始化一個參數個數爲0
                temp = "";
            } else if(A.charAt(i) == '(') {
                bracket.push(A.charAt(i));
            } else if(judgeNumber(A.charAt(i))) {
                temp = temp + A.charAt(i);
                i = i + 1;
                while (judgeNumber(A.charAt(i))) {
                    temp = temp + A.charAt(i);
                    i++;
                }
                i = i - 1;
                number.push(Integer.valueOf(temp));
                if (count.size() > 0) {
                    count.push(count.pop() + 1);    //此處用於計算當前棧頂運算符實際參數個數
                } else {
                    count.push(0 + 1);
                }
                temp = "";
            } else if(A.charAt(i) == '+' || A.charAt(i) == '-' || A.charAt(i) == '*' || A.charAt(i) == '/'){
                // 先將i-1爲獲取前一個值,當前是計算符號
                i = i-1;
                // 初始化前值
                String a = String.valueOf(A.charAt(i));
                if (")".equals(a)){
                    int sum = number.pop();
                    a = String.valueOf(sum);
                    number.push(sum);
                    i = i + 1;
                }else{
                    // i-1往前循環判斷如果有數值類型則字符串相加,比如18+1 檢索到前一個字符爲8 循環判斷之前如果還是數值則相加,結果爲18
                    i = i-1;
                    while (judgeNumber(A.charAt(i))){
                        a = A.charAt(i) + a;
                        i--;
                    }
                    // 循環完畢i恢復原始位置
                    i = i + (a.length()+1);
                }

                // 先將i+1爲獲取後一個值,當前是計算符號
                i = i+1;
                // 初始化後值
                String temps = String.valueOf(A.charAt(i));
                // i+1往後循環判斷如果有數值類型則字符串相加,比如1+28 檢索到第一個字符爲2 循環判斷之前如果還是數值則相加,結果爲18
                i = i+1;
                while (judgeNumber(A.charAt(i))){
                    temps = A.charAt(i) + temps;
                    i++;
                }
                // 循環完畢i恢復原始位置
                i = i - (temps.length()+1);
                String b = temps;


                // 得到值,求結果
                int c = 0;
                if (A.charAt(i) == '+'){
                    c = Integer.valueOf(a)+Integer.valueOf(b);
                }if (A.charAt(i) == '-'){
                    c = Integer.valueOf(a)-Integer.valueOf(b);
                }if (A.charAt(i) == '*'){
                    c = Integer.valueOf(a)*Integer.valueOf(b);
                }if (A.charAt(i) == '/'){
                    c = Integer.valueOf(a)/Integer.valueOf(b);
                }
                // 先摘出加號之前的值,我們要存的是總值
                number.pop();
                // push結果數據,count棧不增加,因爲在加號之前已經加過一次參數值當作此次的個數
                number.push(c);
                i = i + 1;
            } else if(A.charAt(i) == ')') {  //此時要進行運算
                bracket.pop();  //棧頂左括號出棧
                String tempOpera = operation.pop();
                int[] N = new int[count.pop()];
                if(!count.empty())
                    count.push(count.pop() + 1);
                for(int j = 0;j < N.length;j++){
                    N[j] = number.pop();
                }
                int result = 0;
                if(tempOpera.equals("add"))
                    result = add(N);
                else if(tempOpera.equals("max"))
                    result = max(N);
                else if(tempOpera.equals("min"))
                    result = min(N);
                else if(tempOpera.equals("doubleMe"))
                    result = doubleMe(N);
                number.push(result);
            }
        }
    }

    public static void main(String[] args) {
        formula();
    }

    public static void formula(){
        JavaCalculate test = new JavaCalculate();
        test.getResult("max(add(min(1,2,4),max(2,18-1,20000/2))+444,4444/12)");
        System.out.println("函數多參數:"+number.pop());
        /*test.getResult("add(min(2,4),max(2,8))");
        System.out.println("規定格式:"+number.pop());
        test.getResult("add(min(1,2,4),max(2,8,12))");
        System.out.println("函數多參數:"+number.pop());
        test.getResult("add(min(5,3-1),max(2,8))");
        System.out.println("錯誤結果:"+number.pop());
        test.getResult("1+add(min(5,3),max(2,8))");
        System.out.println("前綴+:"+number.pop());*/
    }

    public static void speed(){
        JavaCalculate test = new JavaCalculate();
        long sTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++){
            test.getResult("max(add(min(1,2,4),max(2,18-1,20-1)),22)");
        }
        long eTime = System.currentTimeMillis();
        System.out.println("耗時+:"+(eTime-sTime));
    }
}

執行結果:

剩餘問題:

1. 加減乘除只支持兩位

2. 前綴的加減乘除還不支持

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