对于没有涉及到高级计算方法的同学们来说,觉得计算器的算法简单。其实不是的。科学领域的计算方法即不顺手也不容易使用,下面说下我在计算器制作过程中对算法心得。
表达式:(5+6)*4-9*(5/6)
这个为通常的表达式。我们用的最多的,这个叫做中缀表达式。但是这个算式在计算器中式难以解析的。尤其在算式长度很长的时候
所以我们通常我把他转为后缀表达式,前缀就不说了,咱PASS,不怎么用,还是后缀好哇。
后缀:56+4*956/*-
童鞋们有没发现这2中表达式的区别么,有么发现后缀的好处。
后缀3大特点:1.运算操作数顺序和中缀一样
2.没有刮号
3.不存在优先级
我们惊奇的发现这样的表达式是多么的好解析啊,尤其是在计算器中。
所以我们一般要转后缀表达式用来科学计算哦
至于怎么中转后缀呢?
方法有一些,比较常用的就是用栈机制
初始化2个空堆栈,都来不同时候存取。
一个数组或者STRING用来存结果集。
一:中转后
1.先遍历中缀字符
2.如果是操作数把他放入结果集
3.如果是操作符,弹出(POP),直到遇见刮号或优先级低的操作符,压入堆栈中。
4.遇到(,直接压入栈
5.遇到),在遇到(前面弹出所有操作符,在添加到结果集
6,遍历完毕,弹出所有操作符。添加。
二:后缀求值
1.遍历中缀字符
2.如果是操作数把他放入新堆栈
3.如果是操作符,弹出2个操作数执行操作
4,得到的值继续压入堆栈,求值,循环
5,最后剩一下一个值就是结果了。
三:
附加代码把。。
public double chunshi(String f) {
char c;//用于fortogo中字符的识别和比较
StringBuffer sb = new StringBuffer(f);//转换StringBuffer实现在运算式后面增加标记@的功能
sb.append('@');
String fortogo = sb.toString();//在次转换成String用来提取单个字符
char[] anArray;//用来存取从栈中取出的数据,
anArray = new char[100];//不初始化字符不能存储。。。
Stack<Character> mystack = new Stack<Character>();//定义栈用来存运算符的栈
while (fortogo.charAt(allspc) != '@') {//遍历fortogo直到@,也就是最后的标记
c = fortogo.charAt(allspc);//把当前的值给C用于判断
switch (c) {//判断C
case '('://是不是(
mystack.push(new Character(c));//是的话入栈
allspc++;//字符标记下移
break;//跳出
case ')'://实现()的优先级
while (mystack.peek().charValue() != '(') {//保证()中有数据,弹出()中的运算符
anArray[arrspc++] = mystack.pop().charValue();
}
mystack.pop();
allspc++;
break;
case '+'://加减运算的一样。
case '-':
while (!mystack.empty() && mystack.peek().charValue() != '(') {//不为空,而且上个不为(才入栈
anArray[arrspc++] = mystack.pop().charValue();//取得符号前的值入数组
}
mystack.push(new Character(c));//遍历完毕全部弹出
allspc++;
break;
case '*'://乘除一样。。
case '/':
while (!mystack.empty() && (mystack.peek().charValue() == '*' ||//用于限定的入栈条件
mystack.peek().charValue() == '/')) {
anArray[arrspc++] = mystack.pop().charValue();
}
mystack.push(new Character(c));
allspc++;
break;
default:
while ((c >= '0' && c <= '9') || c == '.') {//当输入为数字和.是存入数组
anArray[arrspc++] = c;
allspc++;
c = fortogo.charAt(allspc);
}
anArray[arrspc++] = '#';//在数字后面加上#做标记
break;
}
}
while (!(mystack.empty())) {//把运算符合数据做好联系,好取值
anArray[arrspc++] = mystack.pop().charValue();
}
allspc = 0;//初始化数组标记
int count;//用于double 型的数据提取
double a;//用于提取运算符对应的数据
double b;
double d;//用于计算一步的值
Stack<Double> mystack1 = new Stack<Double>();//定义double栈用来存新的值
while (allspc < arrspc) {//遍历数组
c = anArray[allspc];
switch (c) {//取值并计算
case '+':
a = mystack1.pop().doubleValue();
b = mystack1.pop().doubleValue();
BigDecimal b1 = new BigDecimal(Double.toString(a));
BigDecimal b2 = new BigDecimal(Double.toString(b));
d = b1.add(b2).doubleValue();
mystack1.push(new Double(d));//运算完的值在次存入栈中
allspc++;
break;
case '-':
a = mystack1.pop().doubleValue();
b = mystack1.pop().doubleValue();
BigDecimal b11 = new BigDecimal(Double.toString(b));//math中用于精度的调整下面一样
BigDecimal b22 = new BigDecimal(Double.toString(a));
d = b11.subtract(b22).doubleValue();
mystack1.push(new Double(d));
allspc++;
break;
case '*':
a = mystack1.pop().doubleValue();
b = mystack1.pop().doubleValue();
BigDecimal b111 = new BigDecimal(Double.toString(a));
BigDecimal b222 = new BigDecimal(Double.toString(b));
d = b111.multiply(b222).doubleValue();
mystack1.push(new Double(d));
allspc++;
break;
case '/':
a = mystack1.pop().doubleValue();
b = mystack1.pop().doubleValue();
try {
if (a == 0) {
throw new Exception();
}
d = b / a;
mystack1.push(new Double(d));
allspc++;
} catch (Exception e) {
jTextField1.setText("除数不能为0");
textshow = "";
allspc = 0;
arrspc = 0;
kuanum = 0;
haonum = 0;
Numcount = false;
Symbolcount = false;
Symbolcount2 = false;
Numcount2 = false;
Numcount3 = false;
diancount = 0;
diancount2 = false;
textshow2 = "";
denone = 0;
dentwo = 0;
symbolastrict = true;
zerocount = 0;
denkua = "";
dencount = false;
}
break;
default:
d = 0;//用于取得一个完成的数据
count = 0;
while ((c >= '0' && c <= '9')) {
d = 10 * d + c - '0';
allspc++;
c = anArray[allspc];
}
if (c == '.') {//让.能插入数据中
allspc++;
c = anArray[allspc];
while ((c >= '0' && c <= '9')) {
count++;
d = d + (c - '0') / Math.pow(10, count);
allspc++;
c = anArray[allspc];
}
}
if (c == '#') {//遇到#就完成一个数据的提取在存入
mystack1.push(new Double(d));
}
allspc++;
break;
}
}
return (mystack1.peek().doubleValue());
}