//String s="-3*(244+22/87/(2^3*57))";
String s="-3* (-5 * (-2)+23 4+22 / 87 / (2^3* 57))"; //我测试负号,用这个,值跟上面的一样
求值System.out.println(evaluate(s));
//结果 -732.0016636418633
==========================
之前在百度搜了一个c语言版的,结果发现不是很能正常运行,看了几遍,实在是没看出为啥偶尔运行成功,偶尔运行不成功。。。于是自己动手,按照那思路写了版java的。。。
不过c和java版的差别蛮大的,
c语言字符串逐字处理,直接char *s指针后移s++就行了,java得用下标i去控制。。。
另外我是为了方便,直接用的现成的java.util.Stack,没有自己去构造栈。。。
=========================
代码如下:
/*
所使用的java内部类说明
java.util.Stack栈类,三个方法 push压栈, pop出栈, peek取栈顶的值
String类,方法 indexOf查子串位置(查不到返回-1),length串长度, charAt某位置的字符值, replaceAll字符串替换
StringBuffer类,可变字符串类,可以随时追加长度append,删除delete
*/
public class EvaluateExpression
{
public static void main(String[] args)
{
//String s="-3*(244+22/87/(2^3*57))";
String s="-3* (-5 * (-2)+23 4+22 / 87 / (2^3* 57))"; //我测试负号,用这个,值跟上面的一样
System.out.println(evaluate(s));
//结果 -732.0016636418633
}
public static double operate(double a, char oper, double b) //计算函数Operate
{
switch(oper)
{
case '+': return a+b;
case '-': return a-b;
case '*': return a*b;
case '/': return a/b;
case '^': return Math.pow(a,b);
default : return 0;
}
}
public static boolean isOperators(char ch)
{
//若ch为运算符则返回true,否则返回false
return "+-*/()#^".indexOf(ch) != -1; //查找不到,表示不是运算符
}
public static char precede(char Aop, char Bop)
{
char prior[][] =
{ // 运算符优先级表
// '+' '-' '*' '/' '(' ')' '#' '^'
{'>','>','<','<','<','>','>','<'}, /* '+' */
{'>','>','<','<','<','>','>','<'}, /* '-' */
{'>','>','>','>','<','>','>','<'}, /* '*' */
{'>','>','>','>','<','>','>','<'}, /* '/' */
{'<','<','<','<','<','=',' ','<'}, /* '(' */
{'>','>','>','>',' ','>','>','>'}, /* ')' */
{'<','<','<','<','<',' ','=','<'}, /* '#' */
{'>','>','>','>','<','>','>','>'} /* '^' */
};
int A_index="+-*/()#^".indexOf(Aop);
int B_index="+-*/()#^".indexOf(Bop);
return prior[A_index][B_index];
}
public static double evaluate(String myExpression)
{
myExpression=myExpression.replaceAll("\\s*", "");
//先去除字符串中所有空白
//System.out.println(myExpression);
Stack<Character> OPTR = new Stack<Character>();//运算符栈
Stack<Double> OPND = new Stack<Double>();//数据栈
OPTR.push('#');
StringBuffer tempdata=new StringBuffer();//临时操作数
int i=0;
int len=myExpression.length();
//增加负号处理。两种情况:如果表达式开头的-1 一定是负号;跟着左括号后的-是负号;,,其余是减号
//处理方式,在负号之前数据栈压入0,然后负号也就当减号处理了
if( myExpression.charAt(i)=='-' )
{ //目前i=0,判断首位是不是负号
OPND.push(0.0);
OPTR.push('-');
i++;
}
// while( i<len || OPTR.peek()!='#')
//{ // 两个条件在C语言可以合在一起,C的指针超出也没事,只不过值不对罢了。
// 在Java没法合在一起,会数组下班越界报错。我这成2个whle循环了
while(i<len)
{
char c=myExpression.charAt(i);
if (!isOperators(c))
{
tempdata.append(c);//字符串追加
i++;
if (isOperators( myExpression.charAt(i) ))
{
double tmp=Double.parseDouble(tempdata.toString()); //字符串转换为数值的方法(double)
OPND.push(tmp);
tempdata.delete(0, tempdata.length()); //clear
}
}
else //是运算符
{
if(c=='(' && myExpression.charAt(i+1)=='-')
{ //跟着左括号后的-是负号
OPND.push(0.0);
}
char op=precede(OPTR.peek(), c);
//System.out.println(OPTR.peek() + " " + c + " 比较关系 " + op);
switch (op)
{
case '<': // 栈顶元素优先级低
OPTR.push(c);
i++;
break;
case '=': // 脱括号并接收下一字符
OPTR.pop();
i++;
break;
case '>': // 退栈并将运算结果入栈
char cop=OPTR.pop();
double b=OPND.pop();
double a=OPND.pop();
OPND.push(operate(a, cop, b));
break;
} //switch
} //if (!isOperators(c)) else
}//while
while(OPTR.peek()!='#')
{
char cop=OPTR.pop();
double b=OPND.pop();
double a=OPND.pop();
OPND.push(operate(a, cop, b));
}
return OPND.peek();
}
}