該算法用於求得一個字符串形式的表達式的結果。例如,計算1+1+(3-1)*3-(21-20)/2所得的表達式的值,該算法利用了兩個棧來計算表達式的值,爲此,稱爲雙棧法,其實現簡單且易於理解。但其要求將咱們平時所看到的表達式的模式轉化爲徹底加括號的形式。如表達式,1+1+(3-1)*3-(21-20)/2是咱們平時習慣上的樣子,其徹底加括號的形式爲,(((1+1)+((3+1)*2))-((21-20)/2))。由此可知,計算一個字符串形式的表達式有兩個任務,第一是將輸入的算術表達式轉化爲一個徹底加括號的算術表達式,第二是將一個徹底加括號的算術表達式進行運算,求得運算的結果。爲方便起見,這裏只考慮加減乘除(+、-、×、÷)這四個基本運算html
其基本思想以下:java
運算符的優先級以下表所示:正則表達式
運算符 | +(加)、-(減) | *(乘)、/(除) |
---|---|---|
優先級 | 1 | 2 |
其中,其數值越大的表示其運算符的優先級越高。 |
示例代碼以下:算法
package queueandstack; import java.util.HashMap; import java.util.Map; import java.util.Stack; /** * 該類用於演示使用雙棧法求解算術表達式的結果 * @author 學徒 * */ public class DoubleStackGetResult { public static void main(String[] args) { DoubleStackGetResult ds=new DoubleStackGetResult(); System.out.println(ds.ComplementBrackets("1+1+(3+1)*2-(21-20)/2")); } //該方法用於實現一個符號表 private static Map<String,Integer> getMap() { Map<String,Integer> temp=new HashMap<String,Integer>(); //定義各個運算符的優先級,其中,x和÷字符用於兼容 temp.put("*", 2); temp.put("/", 2); temp.put("×",2); temp.put("÷",2); temp.put("+", 1); temp.put("-",1); return temp; } /** * 該方法用於將輸入的,習慣上的算術表達式轉化爲徹底加括號的形式 * @param input 輸入的習慣上的算術表達式 */ //該符號表用於定義運算符的優先級 private Map<String,Integer> table=getMap(); //該字符串爲用於匹配數字的 private String rexNumber="\\d+"; private String rexOperator="[((+\\-*/×÷))]"; //操做數棧 Stack<String> number=new Stack<String>(); //運算符棧 Stack<String> save=new Stack<String>(); /** * 該方法用於將中序表達式轉化爲後序表達式,並對其轉化後的表達式以字符串的形式進行返回 * @return 後序表達式 */ public String ComplementBrackets(String input) { //用於得到字符串中的數字所組成的數組 String[] numbers=input.split(rexOperator); //用於指示是獲取了第幾個數字數組中的數字總體 int order=0; //用於指示當前字符的指針 int i=0; while(i<input.length()) { //得到當前字符 String thisString=String.valueOf(input.charAt(i)); //當前該字符爲運算符或者括號時,即當前該字符不爲數字時 if(thisString.matches(rexOperator)) { //噹噹前字符不爲左括號或者右括號時(即爲運算符) if(!thisString.matches("[()()]")) { //用於記錄棧頂元素的優先級 int temporary=0; //獲取當前字符的優先級 int present=table.get(thisString); //當操做數的棧不爲空的時候 if(!save.isEmpty()) { //查看棧頂元素的字符以及其優先級 String top=save.peek(); if(!top.matches("[((]")) { temporary=table.get(top); } } //當棧頂元素的操做符的優先級比當前操做符的優先級還要高或者相同時,對其進行彈出操做,直到棧頂元素的優先級比當前操做符的優先級要低 if(temporary>=present) { while(!save.isEmpty()&&table.get(save.peek())>=present) { String number1=number.pop(); String number2=number.pop(); number.push("("+number2+save.pop()+number1+")"); } } save.push(thisString); } //噹噹前的字符爲左括號的時候,直接將其壓入棧中 else if(thisString.matches("[((]")) { save.push(thisString); } //噹噹前的字符爲右括號的時候,將其棧中的元素一直彈出,直至遇到左括號結束,並將左括號彈出 else { while(!save.peek().matches("[((]")) { String number1=number.pop(); String number2=number.pop(); number.push("("+number2+save.pop()+number1+")"); } //彈出其左括號 save.pop(); /*String number1=number.pop(); String number2=number.pop(); number.push("("+number2+save.pop()+number1+")");*/ } i++; } //當前該字符爲數字的時候 if(thisString.matches(rexNumber)) { //用於存儲數字數組中的數字字符串 String numberString=null; do { numberString=numbers[order]; //當數字字符串中的數字不爲空時(因爲可能會是空字符串的出現),將整個中序表達式的字符串的指針進行向右移動 if(!numberString.trim().equals("")) { i+=numberString.length(); order++; break; } else { order++; } }while(true); //將數字直接壓入操做數棧中 number.push(numberString); } } //將棧中剩餘的字符進行彈出 while(!save.isEmpty()) { String number1=number.pop(); String number2=number.pop(); number.push("("+number2+save.pop()+number1+")"); } return number.pop(); } } 運行結果以下: (((1+1)+((3+1)*2))-((21-20)/2))
其基本思想以下:數組
這種方法不難理解,每當算法遇到一個被括號包圍並由一個運算符和兩個操做數組成的子表達式時,它都可以將運算符和操做數的計算結果壓入操做數棧中,這樣的結果就是在輸入中用這個運算所得的值代替了該子表達式,所以,用這個值代替子表達式獲得的結果和原表達式相同,經過反覆運用以上的規律,最終能夠獲得該表達式的解。this
其示例代碼以下:spa
/** * * 用於計算一個徹底加括號的算術表達式的結果 * @param inputStr 其參數爲徹底加括號的算術表達式 * */ public double getResult(String inputStr) { //用於將輸入的字符串分割成數字的正則表達式 String regex="[((+\\-*/×÷))]"; //用於獲取獲得數字 String[] numbers =inputStr.split(regex); int order=0; //兩個棧,一個爲操做數棧,一個爲運算符棧 Stack<String> ops=new Stack<String>(); Stack<Double> vals=new Stack<Double>(); char[] input=inputStr.toCharArray(); //用於遍歷的字符的指針 int index=0; while(index<input.length) { //讀取對應的字符 char ch=input[index]; //忽略左括號 if(ch=='('||ch=='('); else if(ch=='+') ops.push(String.valueOf(ch)); else if(ch=='-'||ch=='-') ops.push(String.valueOf(ch)); else if(ch=='*'||ch=='×') ops.push(String.valueOf(ch)); else if(ch=='/'||ch=='÷') ops.push(String.valueOf(ch)); else if(ch==')'||ch==')') { //當爲右括號的時候,彈出運算符以及操做數,計算結果並壓入棧中 String op=ops.pop(); double v=vals.pop(); if(op.equals("+")) v=vals.pop()+v; else if(op.equals("-")||op.equals("-")) v=vals.pop()-v; else if(op.equals("*")||op.equals("×")) v=vals.pop()*v; else if(op.equals("/")||op.equals("÷")) v=vals.pop()/v; vals.push(v); } else { //用於存儲數字數組中的數字字符串 String numberString=null; do { numberString=numbers[order]; //當數字字符串中的數字不爲空時(因爲可能會是空字符串的出現),將整個中序表達式的字符串的指針進行向右移動 if(!numberString.trim().equals("")) { index+=numberString.length()-1; order++; break; } else { order++; } }while(true); vals.push(Double.parseDouble(numberString)); } ++index; } return vals.pop(); }