<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
觀察一個普通的算式:3+4*5
我們當然知道,應該先計算 4*5 再將這個結果和3相加,就能得到最後的結果。
如果是一個複雜一些的算式:3+4*((5-6)/7+8)
這依然難不倒我們,只要牢記()的優先順序最高,然後是*/,最後是+-就沒問題了,這就是通常的中綴表示法。
但是通過演演算法分析,這樣的表示式,由於每一次都需要判斷優先順序,所以執行的時間應當是O(N^2)。
在表示式很長很複雜的時候,就需要一種更適合計算機的演演算法來計算了。
簡介
逆波蘭表示法(Reverse Polish notation,RPN,或逆波蘭記法),是一種是由波蘭數學家揚·武卡謝維奇1920年引入的數學表示式方式,在逆波蘭記法中,所有操作符置於運算元的後面,因此也被稱為字尾表示法。
逆波蘭記法不需要括號來標識操作符的優先順序。逆波蘭記法中,操作符置於運算元的後面。
例如表達“三加四”時,寫作“3 4 +”,而不是“3 +4”。如果有多個操作符,操作符置於第二個運算元的後面,所以常規中綴記法的“3 - 4 + 5”在逆波蘭記法中寫作“3 4 - 5+”:先3減去4,再加上5。——維基百科逆波蘭表示法詞條。
這種表示法有以下特點:
例如2*3+4*5
你可以這麼計算,2 和 3 相乘的和是 5,把這個數存起來,再計算 4*5 的值,存起來, 最後在計算兩個存在一起的值。寫出來是這樣子的 2 3 * 4 5 * + 。這就是字尾或逆波蘭記法。
採用堆疊實現的過程很簡單,規則如下。
從頭開始讀取。讀取到如果是數位,則將其壓入棧中。如果是一個符號,就取兩次棧頂的元素通過該符號進行計算,再把得到的數壓入棧中。
Java實現
public class PRNCalculator { public static double PRNCal(String PRN){ Stack<Double> stack = new Stack<Double>(); String[] ss = PRN.split(" "); for(int i = 0; i < ss.length; i++){ if(ss[i].matches("\d")) stack.push(Double.valueOf(ss[i])); if(ss[i].matches("[+|-|*|/]")){ double b = stack.pop(); double a = stack.pop(); if(ss[i].equals("+")) stack.push(a + b); if(ss[i].equals("-")) stack.push(a - b); if(ss[i].equals("*")) stack.push(a * b); if(ss[i].equals("/")) stack.push(a / b); } } return stack.pop(); } }
Test類
public class PRNTest { public static void main(String[] args) { String s = "2 3 * 4 5 * + "; double result = PRNCalculator.PRNCal(s); System.out.println("輸入的逆波蘭表示式:" + s); System.out.println("計算結果:" + result); } }
列印結果:
輸入的逆波蘭表示式:2 3 * 4 5 * +
計算結果:26.0
和字尾表示式的計算方法類似,一箇中綴記法轉換到字尾記法,也可以利用堆疊來實現。
從頭開始讀取。如果讀取到的是數位,將其輸出。如果讀取到的是符號,則判斷該符號的優先順序是否高於棧頂或棧為空,是,則壓入棧中;否,則將棧頂輸出並繼續判斷。如果讀取到的是括號,”(“會直接被壓入棧;在讀取到”)”的時候,棧會一直彈出直到遇到”(“。下面是這個轉換的Java實現。
package PRNCalculator; import java.util.Stack; public class PRNCalculator { public static String PRNTansf(String s){ Stack<String> stack = new Stack<String>(); String[] ss = s.split(" "); StringBuffer sb = new StringBuffer(); for(int i = 0; i < ss.length; i++){ if(ss[i].matches("\d")) sb.append(ss[i] + " "); if(ss[i].matches("[+|-|*|/|(|)]")) { if(stack.isEmpty()) { stack.push(ss[i]); } else { if(ss[i].matches("[+|-]")) { while(!stack.isEmpty() && !stack.peek().matches("[(]")) sb.append(stack.pop()).append(" "); if(stack.isEmpty() || stack.peek().matches("[(]")) stack.push(ss[i]); } if(ss[i].matches("[*|/]")){ while(stack.peek().matches("[*|/]") && !stack.peek().matches("[(]")) sb.append(stack.pop()).append(" "); if(stack.isEmpty() || stack.peek().matches("[(]") || stack.peek().matches("[+|-]")) stack.push(ss[i]); } if(ss[i].matches("[(]")) { stack.push(ss[i]); } if(ss[i].matches("[)]")){ while(!stack.peek().matches("[(]")) sb.append(stack.pop()).append(" "); if(stack.peek().matches("[(]")) stack.pop(); } } } } while(!stack.isEmpty()) sb.append(stack.pop()).append(" "); return sb.toString(); } }
* Test類* package PRNCalculator; public class PRNTest { public static void main(String[] args) { String s = "4 + 5 + 8 * ( 6 + 8 * 7 ) / 3 + 4"; String PRN = PRNCalculator.PRNTansf(s); System.out.println("輸入的表示式為:"); System.out.println(s); System.out.println("輸出的逆波蘭表示式為:"); System.out.println(PRN); double result = PRNCalculator.PRNCal(PRN); System.out.println("該表示式計算結果為:"); System.out.println(result); } }
列印結果:
輸入的表示式為:
4 + 5 + 8 * ( 6 + 8 * 7 ) / 3 + 4
輸出的逆波蘭表示式為:
4 5 + 8 6 8 7 * + * 3 / + 4 +
該表示式計算結果為:
178.33333333333334
從左至右掃描表示式
遇到數位時,將數位壓棧,遇到運運算元時,彈出棧頂的兩個數,計算並將結果入棧
重複2直到表示式最右端,最後運算得出的值即為表示式的結果
計算字尾表示式的值:1 2 3 + 4 × + 5 -
從左至右掃描,將1,2,3壓入棧;
遇到+運運算元,3和2彈出,計算2+3的值,得到5,將5壓入棧;
遇到4,將4壓入棧
遇到×運運算元,彈出4和5,計算5×4的值,得到20,將20壓入棧;
遇到+運運算元,彈出20和1,計算1+20的值,得到21,將21壓入棧;
遇到5,將5壓入棧;
遇到-運運算元,彈出5和21,計算21-5的值,得到16為最終結果
public class ReversePolishNotation { public static void main(String[] args) { String notation = "10 2 3 + 4 * + 5 -"; ReversePolishNotation reversePN = new ReversePolishNotation(); Stack<Integer> numStack = new Stack<>(); //以空格分隔上述表示式,存到陣列中 String[] s = notation.split(" "); //遍歷陣列 for (int i = 0; i < s.length; i++) { if (!reversePN.isOperator(s[i])){ //如果不是運運算元,則壓棧 numStack.push(Integer.parseInt(s[i])); } else { //為運運算元,則取出棧頂的兩個數位進行運算 int result = reversePN.calculation(numStack.pop(), numStack.pop(), s[i]); //將結果壓棧 numStack.push(result); } } //迴圈結束,棧中僅剩的一個元素及為結果 System.out.println(numStack.pop()); } //判斷是否是運運算元 public boolean isOperator(String oper){ return oper.equals("+") ||oper.equals("-") ||oper.equals("*") ||oper.equals("/") ; } //計算 public int calculation(int num1, int num2, String oper){ switch (oper){ case "+": return num2 + num1; case "-": return num2 - num1; case "*": return num2 * num1; case "/": return num2 / num1; default: return 0; } } }
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45