用栈来实现表达式求值【Java版】

来源:互联网 发布:促销软件 编辑:程序博客网 时间:2024/05/20 23:36

//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,没有自己去构造栈。。。


=========================

代码如下:




import 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();   
}

}