以下代码来自:https://bbs.csdn.net/topics/380022283
四则运算的主要难点在于,中缀表达式优先级的处理,为方便运算一般都是将中缀表达式转换成后缀表达式,使用的算法一般为场度调度算法。
思想:
需要用到一个List
和一个Stack
,List
用于存放后缀表达式,栈Stack
用于存放待入List
的运算符。
对于给定的中缀表达式字符串,依次读入每个字符执行下列步骤:
1、对于操作数,直接放入后缀表达式。
2、对于运算符因为不知道在它之后有没有优先级比它高的,因此,在栈内没有运算符时,新来的运算符(待入栈的运算符)直接进栈。如果栈内有运算符,那么比较栈顶运算符与新来的运算符的优先级,如果栈顶运算符优先级更高或者相等,说明栈顶的运算符优先级更高或它先来(同级先来先算),则栈顶运算符退栈,新来的运算符继续和后面的栈顶运算符比较,直到它的优先级更大(或者栈空了),它就可进栈了。
3、遍历完了中缀表达式字符串,如果栈没空,就将栈内元素依次存进后缀表达式。
优先级比较:
static final String symbol = "+-*/()"; //运算符
static final String[] priority = {"+-","*/","()"}; //运算符优先级
static Comparator<String> comp = new Comparator<String>()
{
public int compare(String s1,String s2)
{
int n1 = 0, n2 = 0;
for(int i = 0; i < priority.length; i++)
{
if(priority[i].indexOf(s1) >= 0) { n1 = i; }
if(priority[i].indexOf(s2) >= 0) { n2 = i; }
}
return n1 - n2;
}
};
中缀表达式转后缀表达式:
下列代码实现了,将形如2.5*4+(5*5)+55/55+4+5*(55+3)
的中缀表达式转为后缀表达式,不包含单目运算符,允许表达式有多余的空格,对于中缀表达式为null
的、括号不匹配的、表达式不合法的会抛出异常。
public static List<String> infixToSuffix(String expression) throws Exception
{
if(expression == null)
{
throw new Exception("illegal parameter.");
}
expression.replaceAll("\\s*", ""); // "\\s*"为正则表达式,\\s代表空格,*表示0个或者多个
List<String>list = new ArrayList<String>(); //存放后缀表达式
Stack<String> opStack = new Stack<String>(); //运算符栈
StringBuffer buffer = new StringBuffer();
for(char ch : expression.toCharArray())
{
if(symbol.indexOf(ch) >= 0) //是运算符
{
if(buffer.length() > 0) //如果有操作数
{
String v = buffer.toString();
if( !v.matches("\\d+([.]\\d+)?") ) //如果不是形如125或者1235.25的数为非法数字
{
throw new Exception("illegal variable("+v+").");
}
list.add(v);
buffer.delete(0, buffer.length());
}
if(ch == '(') //左括号直接入栈
{
opStack.push(String.valueOf(ch)); //入栈
}
else if(ch == ')')
{ //扩号内运算符退栈,以消括号
String lastOp = "";
while(opStack.size() > 0)
{
lastOp = opStack.pop();
if(lastOp.equals("("))
{
break;
}
else
{
list.add(lastOp);
}
}
if(!"(".equals(lastOp)) //说明括号不匹配
{
throw new Exception("illegal express.");
}
}
else if( opStack.size() > 0)
{
String str = String.valueOf(ch);
String lastOp = opStack.peek(); //不弹出
if(lastOp.equals("(") || comp.compare(str,lastOp) > 0)
{ //如果待入栈的运算符是"("或者优先级比栈顶运算符更高则直接入栈
opStack.push(str);
}
else //优先级更低或相等则把先来运算符退栈,然后再进栈
{
lastOp = opStack.pop();
list.add(lastOp);
opStack.push(str);
}
}
else //还没有运算符
{
opStack.push(String.valueOf(ch));
}
}
else //不是运算符则当作操作数,因为已经去除所有空格,这里不再需要判断空格
{
buffer.append(ch);
}
}
while(opStack.size() > 0)
{
String lastOp = opStack.pop();
if("()".indexOf(lastOp) >= 0)
{
throw new Exception("illegal express.");
}
list.add(lastOp);
}
return list;
}
对后缀表达式进行计算:
public static double calculator(List<String> list) throws Exception
{ //计算
Stack<Double> val = new Stack<Double>();
double result = 0;
while (list.size() > 0)
{
String s = list.remove(0);
if (symbol.indexOf(s) >= 0)
{
double d1 = val.pop();
double d2 = val.pop();
if ("+".equals(s))
{
result = d2 + d1;
}
else if ("-".equals(s))
{
result = d2 - d1;
}
else if ("*".equals(s))
{
result = d2 * d1;
}
else if ("/".equals(s))
{
result = d2 / d1;
}
else
{
throw new Exception ("illigal symbol("+s+").");
}
val.push(result);
}
else
{
if (!s.matches("\\d+([.]\\d+)?"))
{
throw new Exception ("illigal variable("+s+").");
}
val.push(Double.valueOf(s));
}
}
return result;
}
可测试代码:
package calculator; //包
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Stack;
public class Test
{
static final String symbol = "+-*/()"; //运算符
static final String[] priority = {"+-","*/","()"}; //运算符优先级
static Comparator<String> comp = new Comparator<String>()
{
public int compare(String s1,String s2)
{
int n1 = 0, n2 = 0;
for(int i = 0; i < priority.length; i++)
{
if(priority[i].indexOf(s1) >= 0) { n1 = i; }
if(priority[i].indexOf(s2) >= 0) { n2 = i; }
}
return n1 - n2;
}
};
public static void main(String[] args) throws Exception
{
String expression = "2.5*4+(2*5)+54/54+4";
List<String>list = infixToSuffix(expression);
System.out.println(list);
double result = calculator(list); //计算结果
System.out.printf("%.2f\n",result);
}
public static List<String> infixToSuffix(String expression) throws Exception
{
if(expression == null)
{
throw new Exception("illegal parameter.");
}
expression.replaceAll("\\s*",""); // "\\s*"为正则表达式,\\s代表空格,*表示0个或者多个
List<String>list = new ArrayList<String>(); //存放后缀表达式
Stack<String> opStack = new Stack<String>(); //运算符栈
StringBuilder buffer = new StringBuilder();
for(char ch : expression.toCharArray())
{
if(symbol.indexOf(ch) >= 0) //是运算符
{
if(buffer.length() > 0) //如果有操作数
{
String v = buffer.toString();
if( !v.matches("\\d+([.]\\d+)?") ) //如果不是形如125或者1235.25的数为非法数字
{
throw new Exception("illegal variable("+v+").");
}
list.add(v);
buffer.delete(0, buffer.length());
}
if(ch == '(') //左扩号直接入栈
{
opStack.push(String.valueOf(ch)); //入栈
}
else if(ch == ')')
{ //扩号内运算符退栈,以消括号
String lastOp = "";
while(opStack.size() > 0)
{
lastOp = opStack.pop();
if(lastOp.equals("("))
{
break;
}
else
{
list.add(lastOp);
}
}
if(!"(".equals(lastOp)) //说明括号不匹配
{
throw new Exception("illegal express.");
}
}
else if( opStack.size() > 0)
{
String str = String.valueOf(ch);
String lastOp = opStack.peek(); //不弹出
if(lastOp.equals("(") || comp.compare(str,lastOp) > 0)
{ //如果待入栈的运算符是"("或者优先级比栈顶运算符更高则直接入栈
opStack.push(str);
}
else //优先级更低或相等则把先来运算符退栈,然后再进栈
{
lastOp = opStack.pop();
list.add(lastOp);
opStack.push(str);
}
}
else //还没有运算符
{
opStack.push(String.valueOf(ch));
}
}
else //不是运算符则当作操作数,因为已经去除所有空格,这里不再需要判断空格
{
buffer.append(ch);
}
}
if (buffer.length() >0) //最后一个操作数
{
list.add(buffer.toString());
}
while(opStack.size() > 0)
{
String lastOp = opStack.pop();
if("()".indexOf(lastOp) >= 0)
{
throw new Exception("illegal express.");
}
list.add(lastOp);
}
return list;
}
public static double calculator(List<String> list) throws Exception
{ //计算
Stack<Double> val = new Stack<Double>();
double result = 0;
while (list.size() > 0)
{
String s = list.remove(0);
if (symbol.indexOf(s) >= 0)
{
double d1 = val.pop();
double d2 = val.pop();
if ("+".equals(s))
{
result = d2 + d1;
}
else if ("-".equals(s))
{
result = d2 - d1;
}
else if ("*".equals(s))
{
result = d2 * d1;
}
else if ("/".equals(s))
{
result = d2 / d1;
}
else
{
throw new Exception ("illigal symbol("+s+").");
}
val.push(result);
}
else
{
if (!s.matches("\\d+([.]\\d+)?"))
{
throw new Exception ("illigal variable("+s+").");
}
val.push(Double.valueOf(s));
}
}
return result;
}
}