比windows自帶計算器還強的四則復雜運算計算器!
實測隨機打出兩組復雜算式:-7.5 * 6 / ( -2 + ( -6.5 - -5.22 ) )與 7.5+-3*8/(7+2)
windows的科學計算器計算結果分別為:-3.28(錯誤)和9(錯誤),全錯!!!不信的小伙伴可以口算下,
正確答案是:13.71951219512195和4.833333333333334
中綴運算式轉后綴運算式并進行計算的計算器(支持帶負號、括號和小數的加減乘除運算)
一步一步來
假設有這樣一個算式:-7.5 * 6 / ( -2 + ( -6.5 - -5.22 ) )
我們先要將這一字串進行分析,哪些是數字,哪些是符號,(比如:-7.5就是數字)
具體代碼如下:
// 運算式轉中綴運算式(支持小數點,負數,小括號)
public List<String> getList(String expression) {
List<String> exp = new ArrayList<String>();//存放決議后的中綴運算式
String merge = "";
int index = 0;
char ch, ch1 = 0;
boolean flag = false;
expression = expression.replace(" ", "");
while (index != expression.length()) {
ch = expression.substring(index, index + 1).charAt(0);
merge += ch;
if (index < expression.length() - 1) {// 防止下標越界
ch1 = expression.substring(index + 1, index + 2).charAt(0);
if (isOper(ch1)) {
exp.add(merge);
merge = "";
flag = false;
} else if (isOper(ch)) {
if (flag == false && exp.size() > 0) {
exp.add(merge);
merge = "";
flag = false;
}
}
if (ch == '(' && ch1 == '-' || isOper(ch) && ch1 == '-')
flag = true;
}
index++;
}
exp.add(merge);
return exp;
}
接下來就是重頭戲了!!!中綴運算式—>后綴運算式思路分析圖:



遵循以上紅字規則處理第二個左括號“(”后面的元素,直到右括號“)”

將符號堆疊中所有符號彈出加入到集合List中,直到碰到一個與右括號匹配的左括號

以上就是從中綴運算式轉換到后綴運算式的圖解!得:后綴運算式為:7.5 - 6 * 2 - 6.5 - 5.22 - - + /
下面是代碼詳解:
// 中綴運算式轉后綴運算式(有個記錄負號索引的全域變數minus,方便計算)
public List<String> toRPN(String expression) {
List<String> list=getList( expression );
List<String> rPN=new ArrayList<String>();// 用于存放后綴運算式
Stack<String> exp=new Stack<String>();// 用于操作判斷符號
minus=new ArrayList<>();
for (String s : list) {// 將中綴運算式每個元素list遍歷
if (isOper( s )) {// 如果字串是+-*/
if (exp.isEmpty())// 如果堆疊是空,那么就直接入堆疊
exp.push( s );//-7.5*6/(-2+(-6.5- -5.22))
else if (priority( s ) <= priority( exp.peek() )) {// 如果堆疊里面有運算子,那么就和堆疊頂運算子比較優先級
rPN.add( exp.pop() );// 當前運算子優先級小于堆疊頂運算子,就把堆疊頂運算子彈出加入到后綴運算式rPN串列中
exp.push( s );// 然后壓入當前運算子
} else
exp.push( s );
} else if (s.equals( ")" )) {// 如果當前字串是‘)’那么就將堆疊頂字串加入add到List rPN中,直到堆疊頂字串為"("
while (!exp.peek().equals( "(" )) {
rPN.add( exp.pop() );
}
exp.pop();// 一定要記得將左括號(彈出去,代表一對小括號完成計算
} else if (s.equals( "(" ))
exp.push( s );// 如果是左括號就直接入堆疊
else {// 否則就是數字,直接加入rPN中
if (s.charAt( 0 ) == '-') {
rPN.add( s.substring( 1, s.length() ) );
rPN.add( "" + s.charAt( 0 ) );
minus.add( rPN.size() - 1 );//全域變數minus負號索引list集合
} else
rPN.add( s );
}
}
while (!exp.isEmpty()) {// 最后掃描完list后,將堆疊exp中的字串依次加入到rPN后綴運算式串列中
rPN.add( exp.pop() );
}
return rPN;
}
計算后綴運算式思路分析圖:

接下來處理運算子號:

重復以上動作,直到后綴運算式List為空,即得:

后綴運算式計算代碼:
// 后綴運算式list進行計算
public double calcRPN(List<String> rPN) {
Stack<Double> numStack=new Stack<Double>();
boolean flag=false;//用來標記是否處理過負號
for (int i=0; i < rPN.size(); i++) {
if (isOper( rPN.get( i ) )) {
if (rPN.get( i ).equals( "-" )) {//這里判斷兩次,是為了提高查找負號索引位置的效率
for (int j=0; j < minus.size(); j++) {//遍歷后綴運算式集合中記錄的負號的索引下標
if (i == minus.get( j )) {//如果rPN后綴運算式的下標等于minus集合中記錄的負號索引下標
String min=rPN.get( i );//說明此位置的‘-’號,為負號而不是減號
Double num=numStack.pop();//那么就pop出數堆疊,和-拼接
numStack.push( Double.parseDouble( min + num ) );
flag=true;
continue;
}
}
if (flag) {
flag=false;
continue;
}
}//下面就是常規計算,一定要思量上面兩個continue的作用
double num1=numStack.pop();
double num2=numStack.pop();
numStack.push( calc( num1, num2, rPN.get( i ).charAt( 0 ) ) );
} else {//如果是數字就直接丟到數堆疊
numStack.push( Double.valueOf( rPN.get( i ) ) );
}
}
return numStack.pop();
}
接下來是完成源代碼:
public class ReversePolishNotationCalcDemo { List<Integer> minus;//用于記錄符號出現的索引 public static void main(String[] args) { String expression="-7.5*6/(-2+(-6.5- -5.22))";// 7.5 - 6.5 5.22 - - * expression="7.5+-3*8/(7+2)"; ReversePolishNotationCalcDemo rpn=new ReversePolishNotationCalcDemo(); System.out.print( "中綴運算式為:" ); rpn.getList( expression ).forEach( System.out::print ); // for (String s : rpn.getList(expression)) { // System.out.printf("%s ", s); // } System.out.println(); System.out.print( "后綴運算式為:" ); for (String s : rpn.toRPN( expression )) { System.out.printf( "%s ", s ); } System.out.println(); double result=rpn.calcRPN( rpn.toRPN( expression ) ); System.out.println( expression.replace( " ", "" ) + " = " + result ); } // 后綴運算式list進行計算 public double calcRPN(List<String> rPN) { Stack<Double> numStack=new Stack<Double>(); boolean flag=false; for (int i=0; i < rPN.size(); i++) { if (isOper( rPN.get( i ) )) { if (rPN.get( i ).equals( "-" )) { for (int j=0; j < minus.size(); j++) { if (i == minus.get( j )) { String min=rPN.get( i ); Double num=numStack.pop(); numStack.push( Double.parseDouble( min + num ) ); flag=true; continue; } } if (flag) { flag=false; continue; } } double num1=numStack.pop(); double num2=numStack.pop(); numStack.push( calc( num1, num2, rPN.get( i ).charAt( 0 ) ) ); } else { numStack.push( Double.valueOf( rPN.get( i ) ) ); } } return numStack.pop(); } // 中綴運算式轉后綴運算式 public List<String> toRPN(String expression) { List<String> list=getList( expression ); List<String> rPN=new ArrayList<String>();// 用于存放后綴運算式 Stack<String> exp=new Stack<String>();// 用于操作判斷符號 minus=new ArrayList<>(); for (String s : list) {// 將中綴運算式每個元素list遍歷 if (isOper( s )) {// 如果字串是+-*/ if (exp.isEmpty())// 如果堆疊是空,那么就直接入堆疊 exp.push( s );//-7.5*6/(-2+(-6.5- -5.22)) else if (priority( s ) <= priority( exp.peek() )) {// 如果堆疊里面有運算子,那么就和堆疊頂運算子比較優先級 rPN.add( exp.pop() );// 當前運算子優先級小于堆疊頂運算子,就把堆疊頂運算子彈出加入到后綴運算式rPN串列中 exp.push( s );// 然后壓入當前運算子 } else exp.push( s ); } else if (s.equals( ")" )) {// 如果當前字串是‘)’那么就將堆疊頂字串加入add到List rPN中,直到堆疊頂字串為"(" while (!exp.peek().equals( "(" )) { rPN.add( exp.pop() ); } exp.pop();// 一定要記得將左括號(彈出去,代表一對小括號完成計算 } else if (s.equals( "(" )) exp.push( s );// 如果是左括號就直接入堆疊 else {// 否則就是數字,直接加入rPN中 if (s.charAt( 0 ) == '-') { rPN.add( s.substring( 1, s.length() ) ); rPN.add( "" + s.charAt( 0 ) ); minus.add( rPN.size() - 1 ); } else rPN.add( s ); } } while (!exp.isEmpty()) {// 最后掃描完list后,將堆疊exp中的字串依次加入到rPN后綴運算式串列中 rPN.add( exp.pop() ); } System.out.println( "負號出現的索引:" + Arrays.toString( minus.toArray() ) ); return rPN; } // 運算式轉中綴運算式(支持小數點,負數,小括號) public List<String> getList(String expression) { List<String> exp=new ArrayList<String>(); String merge=""; int index=0; char ch, ch1=0; boolean flag=false; expression=expression.replace( " ", "" ); while (index != expression.length()) { ch=expression.substring( index, index + 1 ).charAt( 0 ); merge+=ch; if (index < expression.length() - 1) {// 防止下標越界 ch1=expression.substring( index + 1, index + 2 ).charAt( 0 ); if (isOper( ch1 )) { exp.add( merge ); merge=""; flag=false; } else if (isOper( ch )) { if (flag == false && exp.size() > 0) {//-7.5*6/(-2+(-6.5- -5.22)) exp.add( merge ); merge=""; flag=false; } } if (ch == '(' && ch1 == '-' || isOper( ch ) && ch1 == '-') flag=true; } index++; } exp.add( merge ); return exp; } public boolean isOper(String oper) { return oper.equals( "+" ) || oper.equals( "-" ) || oper.equals( "*" ) || oper.equals( "/" ); } public boolean isOper(char oper) { return oper == '+' || oper == '-' || oper == '*' || oper == '/' || oper == '(' || oper == ')'; } public int priority(String s) { if (s.equals( "+" ) || s.equals( "-" )) return 0; if (s.equals( "*" ) || s.equals( "/" )) return 1; return -1; } public double calc(double num1, double num2, int oper) { switch (oper) { case '+': return num1 + num2; case '-': return num2 - num1; case '*': return num1 * num2; case '/': return num2 / num1; default: break; } return 0; } }完整源代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/198922.html
標籤:其他
下一篇:堆疊與佇列
