文章目录
- 栈实现综合计算器运算
- 1、前缀表达式 (波兰表达式)
- . 思路分析
- 2、中缀表达式
- . 思路分析
- . 代码实现
栈实现综合计算器运算
1、前缀表达式 (波兰表达式)
前缀表达式又称波兰表达式。运算符位于操作数之前。
比如:(3+2)*6-5 对应前缀表达式就是:- * + 3 2 6 5
. 思路分析
计算机从右至左扫描前缀表达式,依次将数字入栈。当遇到运算符,弹出栈顶和次顶两个数进行运算,运算结果再次入栈,遇到下一个运算符,又弹出栈顶和次顶两个数进行运算,运算结果再次入栈,依次类推…最终得到运算结果。
简单示例:
- 3 2 6 5
- 遇5,入栈
- 遇6,入栈
- 遇2,入栈
- 遇3,入栈
- 遇+,弹出栈顶和次顶两数,3和2进行运算,即3+2=5,5入栈
- 遇*,弹出栈顶和次顶两数,5和6进行运算,即5*6=30,30入栈
- 遇-,弹出栈顶和次顶两数,30和5进行运算,即30-5=25,25入栈
- 最后栈中数即为结果。
2、中缀表达式
中缀表达式就是日常生活中经常使用的表达式,中缀表达式对于人来说是十分好理解的,但是对于计算机来说,操作起来十分麻烦,要去考虑运算符的优先级以及括号的情况等,还需要两个栈来辅助计算,大大增加了内存的开销。一般会将中缀表达式转为其他表达式进行运算操作。(一般转为后缀表达式)
. 思路分析
准备两个栈,一个数栈,一个符号栈。
入栈规则:
- 从头开始依次遍历整个运算式子
- 遇到数字直接入栈
- 遇到符号:
- 如果符号栈为空,那么直接入栈;
- 如果要入栈的符号优先级别小于或等于栈顶的符号,那么就将符号栈栈顶的符号pop出来,再将数栈pop出两个数字进行运算,将运算结果放入数栈,再将要入栈的符号放入符号栈;
- 如果要入栈的符号优先级别大于栈顶的符号,那么就直接入符号栈。
- 最后依次将数栈的元素pop出来,符号栈的元素pop出来,顺序运算即可得到最终结果。
简单示例,建议根据描述画图理解:
6+2*5-3
步骤:
- 遇到6,直接入数栈
- 遇到+,符号栈中为空,直接入符号栈
- 遇到2,直接入数栈
- 遇到*,此时*与符号栈栈顶的+相比,*优先级别大于+,因此直接入符号栈
- 遇到5,直接入数栈
- 遇到-,此时-与符号栈栈顶的*号相比,-优先级别小于*,因此将*号pop出来,数栈pop两个数进行运算,即5*2=10,将10放入数栈,再将-号放入符号栈
- 遇到3,直接入数栈
- 此时已将式子遍历完,依次将数栈,符号栈pop出来运算
- 数栈pop出3,符号栈-,数栈pop出10,运算:10-3=7 (当是-或者/,记住先出栈的为被减数或被除数),将结果放入数栈
- 数栈pop出7,符号栈pop出+,数栈pop出6,运算:7+6=13,将结果放入数栈中,即最终结果
. 代码实现
不考虑括号运算符,只考虑加减乘除的整数运算,该代码只是用于理解栈和思路,计算器的实现代码仅供参考,不是最优解
public class InfixCalculator {
public static void main(String[] args) {
String expression = "60+2*50-3";
if(!expression.isEmpty()){
InfixStack numStack = new InfixStack(expression.length()); // 数栈
InfixStack operStack = new InfixStack(expression.length()); // 符号栈
int index = 0; // 用于遍历表达式
String num = ""; // 用于存储数字
int oper = 0; // 用于存储符号
while (true){
// 获取数字
char oneChar = expression.charAt(index);
num += oneChar;
// 判断下一个字符是不是数字,是数字就加入到num中,不是就跳出
while (true){
if(index < expression.length()-1){ // 判断是否越界
if(numStack.isNumber(expression.charAt(index+1))){
num += expression.charAt(index+1);
index++;
}else {
index++;
break;
}
}else {
break;
}
}
// 将数字结果放入数栈中
numStack.push(Integer.parseInt(num));
// 记录数字的字符串置空
num = "";
// 运算符获取
if(index < expression.length()-1){
oper = expression.charAt(index);
if(!operStack.isEmpty()){
// 判断符号栈中的符号与要入栈符号的优先级别,优先级别小于或等于,
// 就进行运算操作,把运算结果放入数栈中
if(operStack.operPriority(oper)
<= operStack.operPriority(operStack.peek())){
int num1 = numStack.pop();
int num2 = numStack.pop();
char operation = (char) operStack.pop();
int res = operStack.calculator(num1, num2, operation);
numStack.push(res);
}
}
// 如果符号栈为空或者优先级别大于栈顶符号,就直接入栈
operStack.push(oper);
}else {
// 如果字符串已经遍历完了,就执行最后的运算,
// 符号栈中已经为空,说明已运算完
while (!operStack.isEmpty()){
int num1 = numStack.pop();
int num2 = numStack.pop();
char operation = (char) operStack.pop();
int res = operStack.calculator(num1, num2, operation);
numStack.push(res);
}
break;
}
index++;
}
System.out.println(expression+"="+numStack.pop());
}else {
System.out.println("表达式无效...");
}
}
}
class InfixStack{
private int maxSize;
private int top = -1;
private int arr[];
public InfixStack(int maxSize) {
this.maxSize = maxSize;
this.arr = new int[maxSize];
}
public boolean isFull(){
return top == maxSize-1;
}
public boolean isEmpty(){
return top == -1;
}
public int pop(){
if(!isEmpty()){
int value = arr[top];
top--;
return value;
}else {
throw new RuntimeException("栈空...");
}
}
public boolean push(int val){
if(!isFull()){
top++;
arr[top] = val;
return true;
}else {
throw new RuntimeException("栈满...");
}
}
public int peek(){
if(!isEmpty()){
return arr[top];
}else {
throw new RuntimeException("栈空...");
}
}
public boolean isNumber(int num){
if( (0<=num && num<=9) || ('0'<=num && num<='9')){
return true;
}else {
return false;
}
}
public int operPriority(int oper){
if(oper == '*' || oper == '/'){
return 1;
}else if (oper == '+' || oper == '-'){
return 0;
}else {
throw new RuntimeException("运算符有误...");
}
}
public int calculator(int num1, int num2, char oper){
int result = 0;
switch (oper){
case '+':
result = num1 + num2;
break;
case '-':
result = num2 - num1;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num2 / num1;
break;
default:
break;
}
return result;
}
}
60+2*50-3=157