该算法用于求得一个字符串形式的表达式的结果。例如,计算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(); }