使用栈实现计算四则运算

时间:2022-12-15 20:37:50

问题:
刚开始学JAVA时候写一个简易计算器是很容易的,比如说让用户输入一个表达式1+2=?,我们只需要判断给定两个int,一个String,变量就可以直接运算出来。
然而用户输入的是一个四则运算表达式呢?
比如:
2+3*2=?
3+2-1=?
2*(1+3)-6-(2/1)=?
3+(2*(1+2))=?
我们可以发现在这些算式中有两个问题:
1.算式长度不定
2.需要考虑优先级
需要计算出这样的算式我们需要做两件事:
1.将算式转化成后缀表达式
2.使用后缀表达式进行计算
这里先不用思考使用后缀表达式是怎么计算出来结果的,我们先来弄清楚怎么将算式转化成后缀表达式,我们来从第一个最简单的算式开始转化。

1+2的转化:

我们首先要创建一个栈(myStack)来储存算式中出现的运算符,再使用一个字符串(result)来保存结果。
然后我们开始从算式的开头逐个取出字符,如果字符是数字0-9,我们就直接加入result,如果取出的是运算符‘+-*/’就将符号压入符号栈中。
当所有字符都录入之后,将符号栈中的字符取出到result。
如图:
使用栈实现计算四则运算
现在我们得到了一个后缀表达式“12+”。
那我们得到了一个后缀表达式后怎样计算结果呢?
解决方法也是使用一个储存整形值的栈,在这里我创建一个栈叫做numberStack,计算结果为result。
过程如图:
使用栈实现计算四则运算
如果取出的字符为数字,则将数字压入栈中,如果取出的为运算符,则取出numberStack中了两个数字,进行运算符指定的规则运算。
第一步取出1,压入numberStack
第二步取出2,压入numberStack
第三步取出+,取出numberStack中的1和2,并存入num1和num2中。
第四部按照加法运算法则运算re = num1 + num2。
第五步后缀表达式到达结尾,返回结果result。
这个比较简单,那么再来求下一个

2+3*2=?

在这个算式中发现一个乘号,当然*号的优先级要大于+号,那么我们就需要考虑到比较优先级了。
和上面的例子相同我们需要对当前取出的字符和已经存在在字符栈中的字符做一个优先级的比较,如果优先级大于已存在字符栈中的最顶部的符号就不要着急将字符加到resultString当中,而等到输入结束再按照后进先出的顺序将运算符加入到resultString中。
如图:
使用栈实现计算四则运算
那我们现在对后缀表达式进行运算:
使用栈实现计算四则运算

如果当前字符优先级比字符栈中最顶部的字符小或者相等,那就应该直接将栈中的字符加入到result,然后再将当前字符压入字符栈中。
比如对于算式

3+2-1=?

如图:
使用栈实现计算四则运算

计算:
使用栈实现计算四则运算
在这次运算中出现了减法,在减法运算中需要考虑减数和被减数的顺序,我们只需要按照先出来的为减数,后出来的为被减数。
比如3-2的后缀表达式的为32-,可以看见被减数总是放在前面,这说明从栈中取出数字的时候被减数总是后取出来的那个数。(除数和被除数也遵循这个规律)

2*(1+3)-6-(2/1)=?

对于有括号的算式,我们就只需要等待把一对括号都录入之后再将符号加入resultString就可以了。
使用栈实现计算四则运算
运算:
使用栈实现计算四则运算

3+(2*(1+2))=?

使用栈实现计算四则运算

运算:
使用栈实现计算四则运算

好了,方法说完了上代码:

public class MyStack{
private int top;
private char[] menbers;
private int maxSize;

public MyStack(int value){
this.maxSize = value;
menbers = new char[maxSize];
top = -1;
}
public void push(char menber) {
if(!isFull()){
menbers[++top] = menber;
}else{
System.out.println("Stack is full");
}

}

public char pop() {
if(!isEmpty()){
return menbers[top--];
}
return '$';
}

public boolean isFull() {

return top == maxSize-1;
}

public boolean isEmpty() {

return top==-1;
}

public void disp(){
for(int i = 0;i<=top;i++){
System.out.print(menbers[i]+" ");
}
}

}
public class Entry{
String result = "";
MyStack symbolStack = new MyStack(20);
public static void main(String[] args){
String inputStr = "";

try {
Entry e = new Entry();
while(!(inputStr = getString()).equals("end")){

double result = e.start(inputStr);
System.out.println("计算结果:"+result);
}


} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
//获得用户输入
public static String getString() throws IOException{
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReader(input);
String s = buf.readLine();
return s;
}
//获得后缀表达式
public String getPRString(String input){
result = "";
for(int i=0;i<input.length();i++){
char ch = input.charAt(i);
//System.out.print(ch + " ");
switch(ch){
case '/':
case '*':
//判断优先级
prio(ch,2);
break;
case '+':
case '-':
prio(ch,1);
break;
case '(':
symbolStack.push(ch);
break;
case ')':
//括号内的表达式结束,将符号加入到结果中
while(!symbolStack.isEmpty()){
char chx = symbolStack.pop();
if(chx != '('){
result = result + chx;
}else{

break;
}
}
break;
//为数字的话直接录入
default:
result = result + ch;
break;
}



}
//整个表达式结束,清空储存的运算符
while(!symbolStack.isEmpty()){
result = result + symbolStack.pop();
}
System.out.println("后缀表达式:"+result);
return result;
}
//比较优先级
private void prio(char ch, int per) {

while(!symbolStack.isEmpty()){
int per2;
//取出字符栈中的顶部的字符
char theTop = symbolStack.pop();
//如果为“(”那么就重新放回去,结束比较
if(theTop == '('){
symbolStack.push(theTop);
break;
}else{
//将字符栈中的顶部的字符和正在录入的字符比较优先级
if(theTop == '+' || theTop == '-'){
per2 = 1;
}else{
per2 = 2;
}
//如果优先级大于栈中的顶部字符,那么就将当前的字符加入到字符栈中
if(per > per2){
symbolStack.push(theTop);
break;
}else{
//否则将顶部字符加入到结果中
result = result + theTop;
break;
}
}

}
symbolStack.push(ch);
}

public double start(String input){
String prResult = "";
//创建一个储存数字的栈
NumberStack numberStack = new NumberStack(40);
//获得后缀表达式
prResult = getPRString(input);
double result = 0;
for(int i=0;i<prResult.length();i++){
char ch = prResult.charAt(i);
//如果是0到9,就将字符转化成数字存到栈中
if(ch>='0'&&ch<='9'){
double number = ch - '0';
numberStack.push(number);
}else{
//如果是运算符,就取出栈中的最后进入的两个数字
double num1 = numberStack.pop();
double num2 = numberStack.pop();
//开始运算
switch(ch){
case '-':
result = num2 - num1;
//将运算结果重新压入栈,替换运算前的两个数字
numberStack.push(result);
break;
case '+':
result = num1 + num2;
numberStack.push(result);
break;
case '*':
result = num1 * num2;
numberStack.push(result);
break;
case '/':
result = num2 / num1;
numberStack.push(result);
break;


}
System.out.println(result);
}

}
return result;
}

}

如果您发现错误,请指出,共同进步:D