源程序来源于:http://bbs.tarena.com.cn/viewthread.php?tid=102826&extra=&page=1
这里主要对该程序的运行进行基本的分析,搞清楚其原理。因为我本人原来在参加面试的时候遇到过这样的问题,当时就没有答上来,有点后悔,所有这里补补。
这个程序主要采用的是将数进行压栈的方式,我们知道栈的方式是先进后出,一直遇到当前阶段优先级最高的才做运算,如这个表达式:"1+2*(3+4)",这里的数字栈和运算符分别变化如下:
栈数/符的推入就不例出来了,这里主要例当遇到最高级别的运算符的时候,如何进行运算的:
数字栈:1234
运算符栈:#+*(+
===========================
数字栈:127
运算符栈:#+*(
===========================
数字栈:127
运算符栈:#+*
===========================
数字栈:114
运算符栈:#+
===========================
数字栈:15
运算符栈:#
===========================
到这里根据条件就运算完了,就得到了我们想要的结果。源程序如下:
import java.util.Stack;
public class MyCal {
// 运算符优先级比较函数
static int co(char a, char b) {
if (a == '+' || a == '-') {
if (b == '+' || b == '-' || b == ')' || b == '#')
return 1; // a>b
return -1; // ab
}
if (a == '(' || a == '#') {
if (a == '(' && b == ')')
return 0; // a==b
else if (a == '(' && b == '#')
return 2; // can't compare
else if (a == '#' && b == ')')
return 2;
else if (a == '#' && b == '#')
return 0;
else
return -1;
}
if (a == ')') {
if (b == '(')
return 2;
else
return 1;
}
return 0;
}
// 判断表达式中数字的函数
boolean isnum(char ch) {
if ((ch >= '0' && ch <= '9') || ch == '.')
return true;
return false;
}
// 判断表达式中运算符的函数
static boolean issign(char ch) {
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' ||
ch == ')' || ch == '#')
return true;
return false;
}
// 计算最简表达式值的函数
// a和b是操作数,s是运算符
static double cal(double a, char s, double b) {
if (s == '+')
return a + b; // a+b返回a+b的值
if (s == '-')
return b - a; // 由于操作数出栈顺序是后进先出,所以减法和除法要、返回值表达式中要交换参数的顺序
if (s == '*')
return a * b; // a*b返回a*b的值
if (s == '/')
return b / a; // 同减法
return 0;
}
// 计算整个表达式值的函数
static double calculate(String s) {
s += "#";
int i = 0; // 表达式循环条件
char c; // 表达式中的一个字符
Stack<double> num = new Stack<double>(); // 操作数栈
Stack<character> op = new Stack<character>(); // 操作符栈
op.push('#'); // 表达式开始的标志
c = s.substring(i, i + 1).charAt(0); // 取出表达式中的一位
while (c != '#' ||
op.peek().toString().charAt(0) != '#') // 没有取到表达式开始或结束的标志'#',就循环计算表达式的值
{
if (!issign(c)) // 取到的字符是数字,那么就要取出整个数字
{
int start = i;
int end = 0;
while (!issign(s.substring(i, i + 1).charAt(0)))
// 只要s[i]是数字,就表示一个数还没完
end = i++; // 循环条件自加
double m =
Double.parseDouble(s.substring(start, end + 1)); // 取出从i位开始的数字
num.push(m); // 数字入栈
c = s.substring(i, i + 1).charAt(0); // 下一个字符
} else // 取到的字符是运算符
{
switch (co(op.peek(), c)) // 与栈中的运算符比较优先级
{
case -1: // 栈中运算符优先级小于当前运算符
op.push(c); // 运算符入栈
i++;
c = s.substring(i, i + 1).charAt(0);
break;
case 0: // 栈中运算符优先级等于当前运算符
op.pop(); // 运算符出栈
i++;
c = s.substring(i, i + 1).charAt(0);
break;
case 1: // 栈中运算符优先级大于当前运算符
// 两次取出操作数栈中的数
double a = num.pop();
double b = num.pop();
// 取出运算符栈中的运算符
char ss = op.pop();
// 计算结果保存在数字栈中
num.push(cal(a, ss, b));
break;
}
}
}
return num.peek(); // 表达式计算完毕,返回数字栈中保存的计算结果
}
//测试
public static void main(String[] args) {
System.out.println(MyCal.calculate("1+2*(3+4)"));
//System.out.println(MyCal.calculate("1+2*3+5+Math.max(1,3)"));
}
}<pre></pre></character></character></double></double>
本文介绍了一个使用栈来解析和计算数学表达式的Java程序。通过分析1+2*(3+4)等表达式,详细解释了数字栈和运算符栈的工作原理。文章最后给出了完整的源代码。
1477

被折叠的 条评论
为什么被折叠?



