Java 逆ポーランド記法とスタック操作による四則計算機 ソースコード2022年08月12日 11:31


/** *********************************** */
/*  逆ポーランド記法とスタック操作による四則計算機  */
/** *********************************** */

import java.awt.*;
import java.util.Deque;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;

public class algopol extends java.applet.Applet {
    TextField txtPorand, txtAns;
    Button btnKeisan;
    TextField txtMoto;
    Button btnHenkan;

    public void start() {
        txtMoto = new TextField(20);
        btnHenkan = new Button("変換");
        txtPorand = new TextField(20);
        txtAns = new TextField(20);
        btnKeisan = new Button("計算");

        txtMoto.setText("元の計算式");
        txtPorand.setText("逆ポーランド式");
        txtAns.setText("計算結果");

        add(txtMoto);
        add(btnHenkan);
        add(txtPorand);
        add(btnKeisan);
        add(txtAns);
    }

    public boolean action(Event evt, Object what) {
        if (evt.target == btnHenkan) {
            txtPorand.setText(toRPN(txtMoto.getText()));
        }
        if (evt.target == btnKeisan) {
            //r=res(stf.getText()); /* 書かれた式を計算 */
            //rf.setText(String.valueOf(r)); /* 結果を表示 */
            txtAns.setText(parseRPN(txtPorand.getText()));
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        // TODO code application logic here
        new MyFrame("逆ポーランド式 四則計算機", new algopol(), 500, 500);
    }

    /** <h1>逆ポーランド記法(Reverse Polish Notation)[=後置記法:postfix notation]を計算する</h1>
     * <p>
     * スペースで区切った "10 20 30 * +" のような形式。連続した空白は1つ分の空白として処理される。
     * <br>四則演算(+, -, *, /)と括弧のみ。</p>
     *
     * @param rpn : 逆ポーランド記法での計算式
     * @return<b>int</b> : 計算された値
     */
    public static final String parseRPN(final String rpn) {
        final Deque<String> stack = new ArrayDeque<String>();
        double aa, bb;

        String s = rpn.replaceAll("\\s+", " ");    //連続した空白文字をスペース1つ分に置き換える
        final String[] arr = s.trim().split(" ");

        for (String e : arr) {
            if ('0' <= e.charAt(0) && e.charAt(0) <= '9') {    //数字
                stack.push(e);
            } else {
                aa = Double.parseDouble(stack.pop());
                bb = Double.parseDouble(stack.pop());
                if (e.equals("*")) {
                    stack.push(String.valueOf(bb * aa));
                } else if (e.equals("/")) {
                    stack.push(String.valueOf(bb / aa));    // div/0 でInfinityとなる
                } else if (e.equals("+")) {
                    stack.push(String.valueOf(bb + aa));
                } else if (e.equals("-")) {
                    stack.push(String.valueOf(bb - aa));
                }
            }
        }
        return stack.pop();
    }

    /**
     * 逆ポーランド記法用の演算子優先順位
     */
    @SuppressWarnings("serial")
    static final Map<Character, Integer> rpnRank = new HashMap<Character, Integer>() {
        {//ブロックで記述
            put('(', 4);    //※数値が高いほど、優先順位が高いとする
            put('#', 3);    //オペランド(数値)[キーはダミー]
            put('*', 2);
            put('/', 2);
            put('+', 1);
            put('-', 1);
            put(')', 0);
        }
    };

    /** <h1>式を逆ポーランド記法(Reverse Polish Notation)[=後置記法:postfix notation]に変換する</h1>
     * <p>
     * スペースを含まない "10+20*30-40+50" のような式。空白文字は全て除去される。
     * <br>四則演算(+, -, *, /)と括弧のみ。除算は整数除算(小数点以下切り捨て)。</p>
     *
     * @param expression : 変換する式
     * @return<b>String</b> : 逆ポーランド記法に変換された式
     */
    public static final String toRPN(final String expression) {
        final Deque<Character> stack = new ArrayDeque<Character>();

        String s = expression.replaceAll("\\s+", "");    //空白文字を取り除く
        s = "(" + s + ")";                //末尾に")"を付けることで、最後にスタックを吐き出させる
        final int len = s.length();

        String ans = "";    //戻値用(RPN式)バッファ
        String tmp = "";    //数字用バッファ
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            if ('0' <= c && c <= '9') {
                tmp += c;    //数字1文字ずつのため
            } else {
                if (!tmp.equals("")) {
                    if (ans.length() > 0) {
                        ans += " ";
                    }
                    ans += tmp;
                    tmp = "";
                }
                while (!stack.isEmpty() && rpnRank.get(stack.peek()) >= rpnRank.get(c) && stack.peek() != '(') {
                    if (ans.length() > 0) {
                        ans += " ";
                    }
                    ans += stack.pop();
                }
                if (c == ')') {
                    stack.pop();    //'('
                } else {
                    stack.push(c);
                }
            }
        }
        return ans;
    }
}



コメント

トラックバック

このエントリのトラックバックURL: http://tukasa.asablo.jp/blog/2022/08/12/9517102/tb

<< 2022/08
01 02 03 04 05 06
07 08 09 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

このブログについて

ネットで見つけたいろいろ雑記

バックナンバー

RSS