5.5栈实现综合运算(中缀表达式)
前缀表达式
1、 又称波兰式,前缀表达式的运算符位于操作数之前,举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6
2、 前缀表达式的计算机求值
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素和次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果
中缀表达式:中缀表达式就是常见的运算表达式,如(3+4)×5-6【就是我们日常所使用的】。中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作,因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作 (一般转成后缀表达式)【中缀表达式转换成后缀表达式也是一个难点】
后缀表达式
1、 后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后。举例说明: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 –
2、 后缀表达式的计算机求值
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素和栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
使用栈实现综合运算(中缀表达式)
package com.atguigu04.stack;
/**
* @author peng
* @date 2021/11/15 - 20:10
*
* 使用栈来实现加法运算,主要思路:
* 1、创建两个栈,一个用来存放数字,一个用来存放运算符
* 2、读取表达式,判断表达式的字符,如果是数字就进数字栈。如果是符号,且符号栈当前为空,则直接进符号栈;如果当前符号栈不为空,则判断当前符号与
* 栈顶符号的优先级,如果当前符号的优先级大于栈顶符号,则直接进栈;如果当前符号优先级小于栈顶符号,则数字栈弹出两个元素用符号栈的栈顶元素进行运算,
* 将运算后的结果进数字栈,再将当前符号进符号栈
*/
public class Calculator {
public static void main(String[] args) {
String expression = "7*2*2-5+1-5+3-4";
//先创建两个栈,一个数栈,一个符号栈
CalculatorArrayStack numberStack = new CalculatorArrayStack(10);//数栈,用于存放数字
CalculatorArrayStack operStack = new CalculatorArrayStack(10);//符号栈,用于存放符号
char ch;//用来存放表达式中的字符
String keep = "";//用来存放读取的字符串的字符
for (int i = 0; i < expression.length(); i++) {
ch = expression.charAt(i);
if (operStack.isOper(ch)) {//先判断该字符是否是符号
//如果该字符是符号,判断符号栈是否为空
if(!operStack.isEmpty()) {
//如果符号栈不为空,判断当前字符与栈顶符号的优先级
try {
if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
//如果当前符号的优先级小于符号栈栈顶符号的优先级,数栈弹出两个数,符号栈栈顶符号出栈,进行运算
//使用数栈的方法进行运算
int sum = numberStack.cal(numberStack.pop(), numberStack.pop(), operStack.pop());
//再将运算结果压进数栈中
numberStack.push(sum);
//将当前的符号压进符号栈
operStack.push(ch);
}else {
//如果当前符号的优先级大于符号栈栈顶符号的优先级,则当前符号直接进栈
operStack.push(ch);
}
} catch (Exception e) {
e.printStackTrace();
}
}else {
//如果当前符号栈为空,则直接进栈
operStack.push(ch);
}
} else {
//如果是数字,则直接进数字栈
//因为当前的ch是字符,想要将其转换成数字,根据ASCII表,数字字符减去48就可以转变为数字
//numberStack.push(ch - 48);
//不过在这里存在一个大问题,那就是如果要进栈的数字是72,则会出现问题,必须对代码进行优化
keep += ch;//将每一次的读取结果保存下来
//如果当前的字符已经是最后一个字符了也不需要再往下判断了,直接进栈即可
if (i == expression.length() - 1) {
numberStack.push(Integer.parseInt(keep));
break;
}
if (operStack.isOper(expression.charAt(i + 1))) {
//如果下一个字符是运算符,说明数字已经遍历完,可以直接进栈
numberStack.push(Integer.parseInt(keep));
keep = "";
}
}
}
//当全部数字和符号进栈之后,就将数栈中的数和符号栈中的符号取出来进行运算
//最终留在数栈中的数字就是运算结果
int sum = 0;//用来存在运算的结果
while (true) {
if (operStack.isEmpty()) {
break;
}
try {
sum = numberStack.cal(numberStack.pop(), numberStack.pop(), operStack.pop());
numberStack.push(sum);
} catch (Exception e) {
e.printStackTrace();
}
}
try {
System.out.println("该表达式的结果是:" + numberStack.pop());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 定义栈
*/
class CalculatorArrayStack {
private int maxSize;//栈的最大高度
private int[] stack;//使用数组来模拟栈
private int top = -1;//栈指针
public CalculatorArrayStack(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
/**
* 判断栈满
*/
public boolean isFull() {
return top == maxSize - 1;
}
/**
* 判断栈空
*/
public boolean isEmpty() {
return top == -1;
}
/**
* 入栈的操作
*/
public void push(int value) {
if (isFull()){
System.out.println("栈已经满了!");
return;
}
top++;
stack[top] = value;
}
/**
* 出栈的操作
*/
public int pop() throws Exception {
//首先判断栈是否为空
if (isEmpty()) {
//如果栈为空,则抛出异常
throw new Exception("栈为空不能输出数据!");
}
//如果栈不为空
int value = stack[top];
top--;
return value;
}
/**
* 显示栈的情况,遍历时,需要从栈顶开始显示数据
*/
public void list() {
//首先判断栈是否为空
if (isEmpty()) {
System.out.println("当前栈为空!");
return;
}
//如果栈不为空,那么就开始遍历栈
for (int i = top; i > 0; i--) {
System.out.println(stack[i]);
}
}
/**
* 定义运算符的优先级
* 返回的数字越大,优先级越高
*/
public int priority(int oper) {
/*
因为字符在底层是以数字进行存储的,所以可以直接使用数字来进行验证字符
*/
if (oper == '*' || oper == '/') {
return 1;
}else if (oper == '+' || oper == '-') {
return 0;
}else {
return -1;
}
}
/**
* 判断是不是运算符
*/
public boolean isOper(char val) {
return val == '+' || val == '-' || val == '*' || val == '/';
}
/**
* 计算方法
*/
public int cal(int num1, int num2, int oper) {
int sum = 0;//用于保存运算的和
switch (oper) {
case '+':
sum = num2 + num1;//在这里尤其要注意出栈的顺序
break;
case '-':
sum = num2 - num1;
break;
case '*':
sum = num2 * num1;
break;
case '/':
sum = num2 / num1;
break;
default:
break;
}
return sum;
}
/**
* 返回当前的栈顶元素,但并不出栈
*/
public int peek() throws Exception {
//首先判断栈是否为空!
if (isEmpty()) {
throw new Exception("当前栈为空!");
}
int value = stack[top];
return value;
}
}