栈实现计算器
思路:
1:定义表达式 String expression;
2:通过index索引来遍历我们的表达式。
3:如果是数字,则直接入数栈
4:如果是符号则判断符号栈是否有符号
4.1:如果符号栈没有符号,则入符号栈
4.2:如果符号栈有符号,则判断当前符号的优先级是否小于等于符号栈的栈顶符号,如果是,则从数栈中pop两个数,从符号栈中pop一个数进行计算,结果入数栈,再将当前符号入符号栈
4.2.1:如果当前符号的优先级大于符号栈的栈顶符号,则入符号栈
5:当表达是扫描完毕,则顺序从数栈和符号栈pop出数据进行计算,同4.2
6:当符号栈无符号时,数栈的值就是结果
代码如下
栈
// 定义ArrayStack,模拟栈结构
class ArrayStack{
private int maxSize; // 栈的最大容量
private int[] stack; // 数组,数组模拟栈,数据就放在数组中
private int top = -1; // 栈顶,初始化为-1
/***
* @description:
* @param: 定义构造器,初始化栈结果
* @return:
* @author ZhangJiaHao
* @date: 2021/12/3 8:59
*/
public ArrayStack(int maxSize){
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
/***
* @description:
* @param: 判断栈满
* @return: boolean
* @author ZhangJiaHao
* @date: 2021/12/3 9:01
*/
public boolean isFull(){
return top == maxSize - 1;
}
/***
* @description:
* @param: 判断栈空
* @return: boolean
* @author ZhangJiaHao
* @date: 2021/12/3 9:02
*/
public boolean isEmpty(){
return top == -1;
}
/***
* @description:
* @param: 入栈
* @return: void
* @author ZhangJiaHao
* @date: 2021/12/3 9:07
*/
public void push(int number){
// 1:先判断是否栈满
if (isFull()){
System.out.println("栈满");
return;
}
top++;
stack[top] = number;
System.out.println("入栈成功,number:" + number);
return;
}
/***
* @description:
* @param: 出栈
* @return: int
* @author ZhangJiaHao
* @date: 2021/12/3 9:07
*/
public int pop(){
if (isEmpty()){
System.out.println("栈空");
throw new RuntimeException("栈空哟");
}
int value = stack[top];
top--;
System.out.println("出栈成功:number:" + value);
return value;
}
/***
* @description:
* @param: 遍历栈
* @return: void
* @author ZhangJiaHao
* @date: 2021/12/3 9:09
*/
public void list(){
if (isEmpty()){
System.out.println("没有数据,无法遍历");
return;
}
for (int i = top; i >=0 ; i--){
System.out.println(stack[i]);
}
return;
}
/***
* @description:
* @param: 返回运算符的优先级,优先级由自己定义,优先级使用数字来表示,数字越大,优先级越高
* @return: int
* @author ZhangJiaHao
* @date: 2021/12/3 10:45
*/
public int priority(char oper){
if (oper == '*' || oper == '/'){
return 1;
}else if (oper == '+' || oper == '-'){
return 0;
}else {
return -1; // 认为这是有问题的符号
}
}
/***
* @description: 计算的方法
* @param: numer1
* @param: number2
* @param: oper
* @return: int
* @author ZhangJiaHao
* @date: 2021/12/3 10:48
*/
public int cal(int number1, int number2, char oper){
int result = 0; // 用于存放计算结果
switch (oper){
case '+':
result = number1 + number2;
break;
case '-':
result = number2 - number1; //从栈弹出来的,需要用后面的减去前面的
break;
case '*':
result = number2 * number1; //从栈弹出来的,需要用后面的减去前面的
break;
case '/':
result = number2 / number1; //从栈弹出来的,需要用后面的减去前面的
break;
}
return result;
}
/***
* @description: 判断是不是符号
* @param: pan
* @return: boolean
* @author ZhangJiaHao
* @date: 2021/12/3 10:58
*/
public boolean isOper(char oper){
return oper == '+' || oper == '-' || oper == '/' || oper == '*';
}
/***
* @description: 查看栈顶的值,但是不是出栈
* @param:
* @return: int
* @author ZhangJiaHao
* @date: 2021/12/3 11:05
*/
public int peek(){
return this.stack[top];
}
}
计算方法
public static void main(String[] args) {
String expression = "3+2*6-2";
// 先创建两个栈,数栈和符号栈
ArrayStack numberStack = new ArrayStack(10);
ArrayStack operStack = new ArrayStack(10);
// 定义相关变量,扫描字符串的索引
int index = 0;
int num1 = 0;
int num2 = 0;
char oper;
int result;
char ch = ' '; // 将每次扫描到的char保存到ch中
while (true){
// 依次扫描expression的每一个字符
ch = expression.substring(index, index+1).charAt(0);
// 判断ch是什么,然后做相应的处理
if (operStack.isOper(ch)){
// 判断当前的符号栈是不是为空,如果为空,则直接入栈
if (operStack.isEmpty()){
operStack.push(ch);
}else {
// 符号栈中有符号,则需要进行比较优先级
// 当前符号的优先级小于等于栈里的符号的优先级
if (operStack.priority(ch) <= operStack.priority((char) operStack.peek())){
// 从数栈中pop出两个数
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = (char) operStack.pop();
result = numberStack.cal(num1, num2, oper);
numberStack.push(result);
operStack.push(ch);
}else {
// 当前符号的优先级大于符号栈的优先级
operStack.push(ch);
}
}
}else {
numberStack.push(ch - 48); // 这里对应的ch是字符,
}
// index+1,并判断是否扫描到expression的最后
index++;
if (index == expression.length()){
break;
}
}
// 遍历完字符串后,就需要pop出数栈和符号栈进行运算,数栈最后的数字就是结果
// 如果符号栈为空,则计算就结束
while (true){
if (operStack.isEmpty()){
break;
}
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = (char)operStack.pop();
result = numberStack.cal(num1, num2, oper);
numberStack.push(result);
}
System.out.println("表达式:"+expression+"的结果是:"+numberStack.pop());
}
缺陷
上述方法有缺陷,若是计算的数为多位数,则会出现计算错误。
分析
主要的问题就是在于,判断为数字的时候直接入栈,如果后一位还是数字,则会出现计算错误
改进
String expression = "30+21*6-2";
// 先创建两个栈,数栈和符号栈
ArrayStack numberStack = new ArrayStack(10);
ArrayStack operStack = new ArrayStack(10);
// 定义相关变量,扫描字符串的索引
int index = 0;
int num1 = 0;
int num2 = 0;
char oper;
int result;
char ch = ' '; // 将每次扫描到的char保存到ch中
String keepNumber = ""; // 用于拼接多位数
while (true){
// 依次扫描expression的每一个字符
ch = expression.substring(index, index+1).charAt(0);
// 判断ch是什么,然后做相应的处理
if (operStack.isOper(ch)){
// 判断当前的符号栈是不是为空,如果为空,则直接入栈
if (operStack.isEmpty()){
operStack.push(ch);
}else {
// 符号栈中有符号,则需要进行比较优先级
// 当前符号的优先级小于等于栈里的符号的优先级
if (operStack.priority(ch) <= operStack.priority((char) operStack.peek())){
// 从数栈中pop出两个数
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = (char) operStack.pop();
result = numberStack.cal(num1, num2, oper);
numberStack.push(result);
operStack.push(ch);
}else {
// 当前符号的优先级大于符号栈的优先级
operStack.push(ch);
}
}
}else {
// numberStack.push(ch - 48); // 这里对应的ch是字符,
// 判断ch是不是最后以为
if (index == expression.length() -1){
numberStack.push(ch - 48);
}else{
// bug:不能发现是数字就立马入数栈
// 在处理数字时,需要向expression的下一位继续扫描,如果是数,不能立马扫描,需要拼接,如果是符号,则可以入栈
// 定义一个字符串变量用于拼接
// 拼接
keepNumber = keepNumber + ch;
// 判断下一个字符是不是数字
if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
// 后一位是操作符
numberStack.push(Integer.parseInt(keepNumber));
keepNumber = "";
}
}
}
// index+1,并判断是否扫描到expression的最后
index++;
if (index == expression.length()){
break;
}
}
// 遍历完字符串后,就需要pop出数栈和符号栈进行运算,数栈最后的数字就是结果
// 如果符号栈为空,则计算就结束
while (true){
if (operStack.isEmpty()){
break;
}
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = (char)operStack.pop();
result = numberStack.cal(num1, num2, oper);
numberStack.push(result);
}
System.out.println("表达式:"+expression+"的结果是:"+numberStack.pop());
}
上述代码还是具有一些bug,例如开头的数字为负数,不能进行括号的计算等bug需要不断的进行完善。