前置知識:鏈表、隊列、棧、波蘭表達式、中綴表達式和後綴表達式
運行:
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
System.out.println(str + "=" + rpn.execute(str));
}
}
結果:
代碼細節↓
第一步接收輸入,拆分字符串,將運算符和數字分離,存儲到一個鏈表中
public class RPN2
{
//表達式輸入,字符串分解;分離操作符和操作數
public ArrayList<Object> strExecute(String str) throws Exception
{
//將表達式的每個字符用數組鏈表存儲
ArrayList<Object> result = new ArrayList<>();
str = str.trim();
for(int i = 0; i < str.length(); i ++)
{
String op = "";
//若這個字符爲數字,則繼續遍歷下一個元素,直到元素爲非數字
while(str.charAt(i) >= 48 && str.charAt(i) <= 57 || str.charAt(i) == '.')
{
//若爲連續數字,則拼接起來
op += str.charAt(i);
i ++;
if(i >= str.length())
break;
}
//若字符串不等於空,則一定爲數字字符串
if(!op.equals("") && op.length() > 0 && !op.equals(" "))
result.add(Double.valueOf(op)); //將數字字符轉換爲Double類型(方便後續計算)添加至鏈表
if(i >= str.length())
break;
if(str.charAt(i) == ' ') //若爲空格,則跳到下一次循環
continue;
//不爲數字(即操作符)
if(str.charAt(i) < 48 || str.charAt(i) > 57)
{
char op2 = str.charAt(i);
if(op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == '(' || op2 == ')')
result.add(str.charAt(i) + ""); //操作符轉成字符串添加到鏈表
else throw new Exception("不合法的運算符:" + "\"" + op2 + "\"");
}
}
return result; //返回表達式鏈表
}
// 把表達式轉成字符串,方便調試顯示
public String toString(ArrayList<Object> expr)
{
String result = "";
for(Object item: expr)
{
result += item.toString() + " ";
}
return result;
}
單元測試:
將每個字符單元拆分出來,也就是中綴表達式
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
ArrayList<Object> e = rpn.strExecute(str);
System.out.println("拆分後:" + e);
System.out.println("中綴表達式爲:" + rpn.toString(e));
}
}
輸出
第二步將中綴表達式轉換成後綴表達式,後綴表達式我後面會出一篇文章詳解,這裏就先請移步百度
//後綴表達式轉換
public ArrayList<Object> convert(ArrayList<Object> src)
{
ArrayList<Object> dst = new ArrayList<>();
Stack stack = new Stack();
for(Object item : src)
{
if(item instanceof Integer || item instanceof Double) //操作數
{
dst.add(item);
}
else if(item instanceof String) //操作符
{
String op = ((String) item).trim();
int p1 = priority(op); //操作符優先級
if(op.equals("("))
{
stack.push(op);
}
else if(op.equals(")"))
{
//直到匹配到左括號
while(stack.size() > 0)
{
String op2 = (String) stack.pop();
if(op2.equals("(")) break;
dst.add(op2);
}
}
else
{
//從stack彈出操作符,一直到遇到左括號,或者遇到比自己優先級低的符號
while(stack.size() > 0)
{
String op2 = (String) stack.peek(); //僅查看,不彈出
int p2 = priority(op2);
if(op2.equals("(")) //左括號應留在棧內
break;
if(p2 < p1) //遇到比自己優先級低的符號
break;
dst.add(op2);
stack.pop();
}
stack.push(op);
}
}
}
while (stack.size() > 0)
{
dst.add(stack.pop());
}
return dst;
}
//運算符優先級
public int priority(String op)
{
if("+ -".indexOf(op) >= 0) return 1;
if("* /".indexOf(op) >= 0) return 2;
return 0;
}
單元測試:
將中綴表達式轉換成了後綴表達式
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
ArrayList<Object> e = rpn.strExecute(str);
System.out.println("中綴表達式爲:" + rpn.toString(e));
ArrayList<Object> e2 = rpn.convert(e);
System.out.println("後綴表達式爲:" + rpn.toString(e2));
}
}
輸出
將鏈表轉換爲隊列,後面計算需要
//鏈表轉隊列
public Queue<Object> list2Queue(List<Object> list)
{
Queue<Object> queue = new ArrayDeque<>();
Iterator<Object> iterator = list.iterator();
while(iterator.hasNext())
{
queue.add(iterator.next());
}
return queue;
}
最後一步,後綴表達式的計算,返回結果
//後綴表達式計算
public Object calculation(Queue<Object> src)
{
Stack stack = new Stack(); //用於存放操作數
while(src.size() > 0)
{
//從隊列中彈出一個元素
Object item = src.poll();
//若元素爲操作數,則直接入棧
if(item instanceof Double || item instanceof Integer)
{
stack.push(item);
}
//若元素爲操作符,則彈出棧內最上層的兩個操作數進行運算,將結果壓棧
else if(item instanceof String)
{
//操作符(+ - * /)
String op = (String) item;
Double right = (Double) stack.pop(); //彈出一個數
Double left = (Double) stack.pop();
Double sum = 0.0d; //結果
if(op.equals("+"))
sum = left + right;
else if(op.equals("-"))
sum = left - right;
else if(op.equals("*"))
sum = left * right;
else if(op.equals("/"))
sum = left / right;
stack.push(sum); //將計算結果入棧
}
}
return stack.pop(); //最終棧內存儲的是一個計算結果,將之彈出
}
測試代碼:
import java.util.ArrayList;
import java.util.Queue;
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
ArrayList<Object> e = rpn.strExecute(str);
System.out.println("中綴表達式爲:" + rpn.toString(e));
ArrayList<Object> e2 = rpn.convert(e);
System.out.println("後綴表達式爲:" + rpn.toString(e2));
//將後綴表達式的鏈表轉換爲隊列
Queue<Object> queue = rpn.list2Queue(e2);
Object result = rpn.calculation(queue);
System.out.println("結果:" + result);
}
}
輸出
一步到位
//執行計算
public Object execute(String expression) throws Exception
{
//拆分表達式字符串,將數字和運算符分離
ArrayList<Object> str = strExecute(expression);
//將表達式轉換成後綴表達式
ArrayList<Object> suffixEx = convert(str);
//鏈表轉換成隊列,運算時需要用到隊列
Queue<Object> queue = list2Queue(suffixEx);
//返回運算結果
return calculation(queue);
}
}
大功告成,去試試吧!
附上源碼下載地址:https://download.csdn.net/download/qq_41932905/12317704