java實(shí)現(xiàn)任意四則運(yùn)算表達(dá)式求值算法
本文實(shí)例講述了java實(shí)現(xiàn)任意四則運(yùn)算表達(dá)式求值算法。分享給大家供大家參考。具體分析如下:
該程序用于計(jì)算任意四則運(yùn)算表達(dá)式。如 4 * ( 10 + 2 ) + 1 的結(jié)果應(yīng)該為 49。
算法說(shuō)明:
1. 首先定義運(yùn)算符優(yōu)先級(jí)。我們用一個(gè)
Map<String, Map<String, String>>
來(lái)保存優(yōu)先級(jí)表。這樣我們就可以通過(guò)下面的方式來(lái)計(jì)算兩個(gè)運(yùn)算符的優(yōu)先級(jí)了:
/** * 查表得到op1和op2的優(yōu)先級(jí) * @param op1 運(yùn)算符1 * @param op2 運(yùn)算符2 * @return ">", "<" 或 "=" */ public String priority(String op1, String op2) { return priorityMap.get(op1).get(op2); }
2. 掃描表達(dá)式字符串,每次讀入一個(gè) token 進(jìn)行處理。
使用兩個(gè)輔助棧:optStack用于保存運(yùn)算符,numStack用于保存操作數(shù). 我們用 '#' 作為表達(dá)式的起始和結(jié)果標(biāo)志符。
讀入一個(gè)token,如果它是數(shù)字,則壓入numStack棧中;
如果它是運(yùn)算符,則取出optStack棧的棧頂元素A,將 A 與 token 進(jìn)行優(yōu)先級(jí)比較。
如果 A < token,則將 token 壓入optStack棧。
如果 A = token,則說(shuō)明 token和A是一對(duì)括號(hào),此時(shí)將optStack棧的棧頂元素彈出。
如果 A > token,則從numStack中彈出2個(gè)操作數(shù),從optStack中彈出1個(gè)運(yùn)算符,并計(jì)算結(jié)果。
當(dāng)optStrack棧為空時(shí)(即棧頂元素為 '#'),numStack棧的棧頂元素即為表達(dá)式的值。
算法實(shí)現(xiàn):
/** * 算術(shù)表達(dá)式求值。 * 3 + 4 * 12 結(jié)果為51 * @author whf * */ public class EvaluateExpression { // 運(yùn)算符優(yōu)先級(jí)關(guān)系表 private Map<String, Map<String, String>> priorityMap = new HashMap<String, Map<String, String>>(); private LinkedStack<String> optStack = new LinkedStack<String>(); // 運(yùn)算符棧 private LinkedStack<Double> numStack = new LinkedStack<Double>(); // 操作數(shù)棧 /** * 計(jì)算表達(dá)式 * @param exp 四則運(yùn)算表達(dá)式, 每個(gè)符號(hào)必須以空格分隔 * @return */ public double calcualte(String exp) { StringTokenizer st = new StringTokenizer(exp); while (st.hasMoreTokens()) { String token = st.nextToken(); process(token); } return numStack.pop(); } /** * 讀入一個(gè)符號(hào)串。 * 如果是數(shù)字,則壓入numStack * 如果是運(yùn)算符,則將optStack棧頂元素與該運(yùn)算符進(jìn)行優(yōu)先級(jí)比較 * 如果棧頂元素優(yōu)先級(jí)低,則將運(yùn)算符壓入optStack棧,如果相同,則彈出左括號(hào),如果高,則取出2個(gè)數(shù)字,取出一個(gè)運(yùn)算符執(zhí)行計(jì)算,然后將結(jié)果壓入numStack棧中 * @param token */ private void process(String token) { while (false == "#".equals(optStack.getTop()) || false == token.equals("#")) { // token is numeric if (true == isNumber(token)) { numStack.push(Double.parseDouble(token)); break; // token is operator } else { String priority = priority(optStack.getTop(), token); if ("<".equals(priority)) { optStack.push(token); break; } else if ("=".equals(priority)) { optStack.pop(); break; } else { double res = calculate(optStack.pop(), numStack.pop(), numStack.pop()); numStack.push(res); } } } } /** * 執(zhí)行四則運(yùn)算 * @param opt * @param n1 * @param n2 * @return */ private double calculate(String opt, double n1, double n2) { if ("+".equals(opt)) { return n2 + n1; } else if ("-".equals(opt)) { return n2 - n1; } else if ("*".equals(opt)) { return n2 * n1; } else if ("/".equals(opt)) { return n2 / n1; } else { throw new RuntimeException("unsupported operator:" + opt); } } /** * 檢查一個(gè)String是否為數(shù)字 * @param token * @return */ private boolean isNumber(String token) { int LEN = token.length(); for (int ix = 0 ; ix < LEN ; ++ix) { char ch = token.charAt(ix); // 跳過(guò)小數(shù)點(diǎn) if (ch == '.') { continue; } if (false == isNumber(ch)) { return false; } } return true; } /** * 檢查一個(gè)字符是否為數(shù)字 * @param ch * @return */ private boolean isNumber(char ch) { if (ch >= '0' && ch <= '9') { return true; } return false; } /** * 查表得到op1和op2的優(yōu)先級(jí) * @param op1 運(yùn)算符1 * @param op2 運(yùn)算符2 * @return ">", "<" 或 "=" */ public String priority(String op1, String op2) { return priorityMap.get(op1).get(op2); } /** * 構(gòu)造方法,初始化優(yōu)先級(jí)表 */ public EvaluateExpression() { // initialize stack optStack.push("#"); // initialize priority table // + Map<String, String> subMap = new HashMap<String, String>(); subMap.put("+", ">"); subMap.put("-", ">"); subMap.put("*", "<"); subMap.put("/", "<"); subMap.put("(", "<"); subMap.put(")", ">"); subMap.put("#", ">"); priorityMap.put("+", subMap); // - subMap = new HashMap<String, String>(); subMap.put("+", ">"); subMap.put("-", ">"); subMap.put("*", "<"); subMap.put("/", "<"); subMap.put("(", "<"); subMap.put(")", ">"); subMap.put("#", ">"); priorityMap.put("-", subMap); // * subMap = new HashMap<String, String>(); subMap.put("+", ">"); subMap.put("-", ">"); subMap.put("*", ">"); subMap.put("/", ">"); subMap.put("(", "<"); subMap.put(")", ">"); subMap.put("#", ">"); priorityMap.put("*", subMap); // / subMap = new HashMap<String, String>(); subMap.put("+", ">"); subMap.put("-", ">"); subMap.put("*", ">"); subMap.put("/", ">"); subMap.put("(", "<"); subMap.put(")", ">"); subMap.put("#", ">"); priorityMap.put("/", subMap); // ( subMap = new HashMap<String, String>(); subMap.put("+", "<"); subMap.put("-", "<"); subMap.put("*", "<"); subMap.put("/", "<"); subMap.put("(", "<"); subMap.put(")", "="); //subMap.put("#", ">"); priorityMap.put("(", subMap); // ) subMap = new HashMap<String, String>(); subMap.put("+", ">"); subMap.put("-", ">"); subMap.put("*", ">"); subMap.put("/", ">"); //subMap.put("(", "<"); subMap.put(")", ">"); subMap.put("#", ">"); priorityMap.put(")", subMap); // # subMap = new HashMap<String, String>(); subMap.put("+", "<"); subMap.put("-", "<"); subMap.put("*", "<"); subMap.put("/", "<"); subMap.put("(", "<"); //subMap.put(")", ">"); subMap.put("#", "="); priorityMap.put("#", subMap); } }
程序測(cè)試:
String exp = "4 * ( 10 + 2 ) + 1 #"; EvaluateExpression ee = new EvaluateExpression(); out.println(ee.calcualte(exp));
運(yùn)行結(jié)果為 49。
希望本文所述對(duì)大家的C++程序設(shè)計(jì)有所幫助。
- java數(shù)據(jù)結(jié)構(gòu)與算法之中綴表達(dá)式轉(zhuǎn)為后綴表達(dá)式的方法
- java實(shí)現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴的方法
- Java正則表達(dá)式處理特殊字符轉(zhuǎn)義的方法
- Java后綴數(shù)組之求sa數(shù)組的實(shí)例代碼
- JAXB命名空間及前綴_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- 關(guān)于各種排列組合java算法實(shí)現(xiàn)方法
- java字符串相似度算法
- java異或加密算法
- Java實(shí)現(xiàn)幾種常見(jiàn)排序算法代碼
- Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實(shí)現(xiàn)方法詳解
相關(guān)文章
CRC校驗(yàn)原理及其C語(yǔ)言實(shí)現(xiàn)詳解
循環(huán)冗余校驗(yàn)(Cyclic?Redundancy?Check,?CRC)是一種根據(jù)網(wǎng)絡(luò)數(shù)據(jù)包或計(jì)算機(jī)文件等數(shù)據(jù)產(chǎn)生簡(jiǎn)短固定位數(shù)校驗(yàn)碼的一種信道編碼技術(shù)。本文主要介紹了CRC校驗(yàn)原理及其C語(yǔ)言實(shí)現(xiàn),感興趣的可以了解一下2023-03-03Qt自定義控件實(shí)現(xiàn)圓圈加載進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Qt自定義控件實(shí)現(xiàn)圓圈加載進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12C++實(shí)現(xiàn)兩個(gè)有序數(shù)組的合并
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)兩個(gè)有序數(shù)組的合并,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié)
這篇文章主要介紹了c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11全面了解結(jié)構(gòu)體、聯(lián)合體和枚舉類(lèi)型
下面小編就為大家?guī)?lái)一篇全面了解結(jié)構(gòu)體、聯(lián)合體和枚舉類(lèi)型。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07C/C++調(diào)用Fortran的DLL的操作過(guò)程
這篇文章主要介紹了C/C++調(diào)用Fortran的DLL,本文以一個(gè)簡(jiǎn)單的加法器為例,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03C++ 基類(lèi)指針和子類(lèi)指針相互賦值的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇C++ 基類(lèi)指針和子類(lèi)指針相互賦值的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12