[Java]加算、減算、乗算、除算の数式を小数で計算します(単純な計算機)。

今日の練習は

1.キーボードを使用して、数値、角括弧、および加算、減算、乗算、除算の4つの演算記号を含む数式文字列を受け取ります。
2.文字列を分析し、数式を計算します。

インターネットでブログを検索し、問題の解決方法とコード
https://www.cnblogs.com/menglong1108/p/11619896.htmlを説明しました
が、このブログでは小数の計算が行われておらず、変更プロセス中に多くの問題が発生しました。

それは質問を理解する考えについて教えてくれます、おそらくそれを整理します:

  1. 最初に、入力した数学演算式(つまり、中置式)をリストに保存して、後置式に簡単に変換します。

  2. 次に、リスト内のインフィックス式をトラバースし、それらをポストフィックス式に変換します。アイデアは次のとおりです
    。1.演算子を格納するスタックを作成し、サフィックス式を格納するリストを作成します
    2.最初のトラバースリストのインフィックス式は、数値に遭遇したときに新しいリストに配置されます。演算子に遭遇した場合は、個別に説明する必要があります。

    a)演算子スタックが空であるか、スタックの最上位の演算子の優先度が現在トラバースされている演算子の優先度よりも低い場合(たとえば、+および-の優先度が*および/よりも低い)、直接スタックに入る
    b)演算子スタック空ではなく、スタックの最上位の演算子の優先度が現在トラバースされている演算子の優先度以上である場合、スタック操作はループで実行され、現在の演算子よりも優先度の低い要素が見つかるまでリストに追加されます。ループが実行された後、現在の演算子がスタックにプッシュされます。

    3.かっこに移動するとき:左かっこの場合はスタックに直接プッシュし、右かっこが見つかった場合は、左かっこが見つかるまでスタックをループします。注:右括弧が検出された場合にのみ、左括弧がスタックからポップされます
    4.最初のリストをたどった後、スタックの残りを新しいリストに順番にポップし、これがサフィックス式になります。

  3. この時点で、変換されたサフィックス式は新しいリストに格納され
    ます。次のステップは、サフィックス式を評価することです。1.新しいスタックを作成します
    。2。サフィックス式をトラバースし、演算子に遭遇したときに数値をスタックに直接プッシュします。 、次に、スタックの最上部と2番目のスタックの最上部にある2つの数値が、このオペレーターによって操作されます。そして、結果をスタックにプッシュし、最後に残っている唯一のスタック要素を答えとして取得します。

次のpoは、完全なコード(小数を含む)を出力し、コードに小数演算が含まれる場所について詳しく説明します。

package calculation;
/*import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;*/
import java.util.*;
public class calculation {
    
    
	
	private static List<String> parseToSuffixExpression(List<String> expressionList) {
    
    
        //创建一个栈用于保存操作符
        Stack<String> opStack = new Stack<>();
        //创建一个list用于保存后缀表达式
        List<String> suffixList = new ArrayList<>();
        for(String item : expressionList){
    
    
            //得到数或操作符
            if(isOperator(item)){
    
    
                //是操作符 判断操作符栈是否为空
                if(opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())){
    
    
                    //为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符直接压栈
                    opStack.push(item);
                }else {
    
    
                    //否则将栈中元素出栈如队,直到遇到大于当前操作符或者遇到左括号时
                    while (!opStack.isEmpty() && !"(".equals(opStack.peek())){
    
    
                        if(priority(item) <= priority(opStack.peek())){
    
    
                            suffixList.add(opStack.pop());
                        }
                    }
                    //当前操作符压栈
                    opStack.push(item);
                }
            }else if(isNumber(item)){
    
    
                //是数字则直接入队
                suffixList.add(item);
            }else if("(".equals(item)){
    
    
                //是左括号,压栈
                opStack.push(item);
            }else if(")".equals(item)){
    
    
                //是右括号 ,将栈中元素弹出入队,直到遇到左括号,左括号出栈,但不入队
                while (!opStack.isEmpty()){
    
    
                    if("(".equals(opStack.peek())){
    
    
                        opStack.pop();
                        break;
                    }else {
    
    
                        suffixList.add(opStack.pop());
                    }
                }
            }else if(".".equals(item)){
    
    
            	//System.out.print('a');
            	suffixList.add(item);
            }else {
    
    
                throw new RuntimeException("有非法字符!");
            }
        }
        //循环完毕,如果操作符栈中元素不为空,将栈中元素出栈入队
        while (!opStack.isEmpty()){
    
    
            suffixList.add(opStack.pop());
        }
        return suffixList;
    }
    /**
     * 判断字符串是否为操作符
     * @param op
     * @return
     */
    public static boolean isOperator(String op){
    
    
        return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
    }

    /**
     * 判断是否为数字
     * @param num
     * @return
     */
    public static boolean isNumber(String num){
    
    
        return num.matches("^([0-9]{1,}[.][0-9]*)$") || num.matches("^([0-9]{1,})$");
    }

    /**
     * 获取操作符的优先级
     * @param op
     * @return
     */
    public static int priority(String op){
    
    
        if(op.equals("*") || op.equals("/")){
    
    
            return 1;
        }else if(op.equals("+") || op.equals("-")){
    
    
            return 0;
        }
        return -1;
    }
	
    /**
     * 将表达式转为list
     * @param expression
     * @return
     */
    private static List<String> expressionToList(String expression) {
    
    
        int index = 0;
        List<String> list = new ArrayList<>();
        do{
    
    
            char ch = expression.charAt(index);
            if(ch!=46 && (ch <= 47 || ch >= 58)){
    
    
                //是操作符,直接添加至list中
                index ++ ;
                list.add(ch+"");
            }else{
    
    
                //是数字,判断多位数的情况
                String str = "";
                while (index < expression.length() && (expression.charAt(index) >47 && expression.charAt(index) < 58 || expression.charAt(index)==46)){
    
    
                    str += expression.charAt(index);
                    index ++;
                }
                list.add(str);
                //System.out.println(str);
            }
        }while (index < expression.length());
        return list;
    }
    
	/**
     * 根据后缀表达式list计算结果
     * @param list
     * @return
     */
    private static double calculate(List<String> list) {
    
    
        Stack<Double> stack = new Stack<>();
        for(int i=0; i<list.size(); i++){
    
    
            String item = list.get(i);
            if(item.matches("^([0-9]{1,}[.][0-9]*)$") || item.matches("^([0-9]{1,})$")){
    
    
                //是数字
                stack.push(Double.parseDouble(item));
            }else {
    
    
                //是操作符,取出栈顶两个元素
                double num2 = stack.pop();
                //System.out.print(num2);
                double num1 = stack.pop();
                double res = 0;
                if(item.equals("+")){
    
    
                    res = num1 + num2;
                }else if(item.equals("-")){
    
    
                    res = num1 - num2;
                }else if(item.equals("*")){
    
    
                    res = num1 * num2;
                }else if(item.equals("/")){
    
    
                    res = num1 / num2;
                }else {
    
    
                    throw new RuntimeException("运算符错误!");
                }
                stack.push(res);
            }
        }
        return stack.pop();
    }
    
    public static boolean isInt(double calculateResult){
    
    
    	double n = calculateResult - (int)calculateResult;
    	if(n!=0){
    
    
    		return true;
    	}else{
    
    
    		return false;
    	}
    }
	
	public static void main(String []args){
    
    
		Scanner sc = new Scanner(System.in);
        String expression = sc.nextLine();
        List<String> expressionList = expressionToList(expression);
        //System.out.println("中缀表达式转为list结构="+expressionList);
        //将中缀表达式转换为后缀表达式
        List<String> suffixList = parseToSuffixExpression(expressionList);
        //System.out.println("对应的后缀表达式列表结构="+suffixList);
        //根据后缀表达式计算结果
        double calculateResult = calculate(suffixList);
        if(isInt(calculateResult)){
    
    
        	System.out.printf(expression+"=%.2f\n",calculateResult);
        }else{
    
    
        	System.out.printf(expression+"="+ (int)calculateResult);
        }
        sc.close();
}
}

このコードは、前のpoページのコードを最適化します。

  1. 小数を計算できます
  2. 携帯電話のコンピュータのように、最終的な計算結果が整数の場合、出力の回答には小数点が含まれず、計算結果は小数であり、出力の回答は小数です。

具体的な変更点は次のとおりです。

  1. 75行目では、最初のリストの値が数値であるかどうかを判断するときに小数と一致する正規表現を追加しています
  2. 102行目と109行目(最初のリストを書く)は小数点の判定を追加しました、それが小数点の場合はstrにも追加されます
  3. 行129は、小数の計算を追加します
  4. 155行目から162行目では、結果が整数か小数かを追加しています。

結果は次のとおりです。

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_44899247/article/details/107187498