使用数组模拟栈完成表达式计算思路:
- 1)通过index值(索引),来遍历我们的表达式
- 2)如果我们发现是一个数字,就存入数字栈
- 3)如果发现扫描到一个符号,就分如下情况
- (3.1)如果发现符号栈为空,就直接入栈
- (3.2)如果符号栈有操作符,就进行比较,如果当前操作符的优先级小于或者等于栈中的操作符,就需要先操作字符栈中的pop一个符号,然后数字栈pop两个数字,进行运算。将得到的结果,入数字栈,然后将比较时候小的操作符入符号栈。如果当前操作符的优先级大于栈中的操作符,就直接入符号栈。
- 4)当表达式扫描完毕,就顺序的从数字栈和符号栈中分别pop出相应的数和符号并且运行。
- 5)最后数字栈剩下的一个数字就是表达式的结果
修复计算bug:
- 无法计算多位数 个人解决方法:
1)添加一个count=0的计数器,遍历表达式,如果if判断句判断为数字则count++,如果判断为字符那么count–;
2)然后特殊情况是表达式是以负数开头的(例如‘-11-2*2’),这个先看数字栈是否为空,若为空那么就说明这个符号的作用是开头标正负用的。那么判断完就给一个count++,这样count就不会变成负数 - 无法连减的解决方法:
一开始我想着栈中存放的数都为正数,但是一从栈中拿出来两个数和符号进行计算就会出bug。 例如表达式
‘3-2-1’ ,最后结果是2,显然出错了,本来结果是0啊?!
这个错误过程是这样的:
遍历完表达式数字栈有 {3、2、1},字符栈有{‘-’、‘-’}
①首先开始计算时候数字栈取出2、1,字符栈取出 ‘-’
② 然后计算2-1=1又存入了栈中
③此时数字栈中{3、1},字符栈中{‘-’}
④然后数字栈又取出3、1,字符栈取出 ‘-’ 计算得到3-1=2
栈都是先存后取的,如果连减就会出问题。
个人解决方法:
创建int isNegative=0;其作用是判断一个数字为正负,0为非负数,1为负数。
每次遇到负号就将其变为正号存入字符栈,并且让isNegative+1。如果表达式遍历到数字之后那么根据isNegative是否为1,就知道存入前是否乘(-1)
这样数字栈里就有正负了,最后让isNegative=0等待下一次循环。
import org.junit.Test;
public class Calculator {
@Test
public void test1() {
String ex = "-12+20*3-2*2-1";
NumStack num = new NumStack(100);//创建数字栈,大小为100
CharStack cc = new CharStack(50);//创建字符栈,大小为50
char[] arr = ex.toCharArray();//将表达式转换成字符串一个一个处理
int index = 0;//索引,用来扫描
int num1 = 0;//接收数字栈的出栈值
int num2 = 0;//接收数字栈的出栈值
char oper;//接收字符栈的出栈值
int res = 0;//接收结果
int isNegative=0;//判断一个数字为正负,0为非负数,1为负数
int count=0;//计数器,1代表一位,0代表零位,以此类推
while (true) {
if (index == arr.length) {
System.out.println("表达式遍历完毕!");
break;
}
char ch = arr[index++];
if (cc.isOper(ch)) {//如果是字符//
count--;
if (!cc.isEmpty()) {//如果字符栈不为空
if (cc.priority(ch) < cc.priority(cc.peek())) {//如果要添加到栈的字符优先度小于栈中要出的字符
num1 = num.pop();
num2 = num.pop();
oper = cc.pop();
res = cc.cal(num1, num2, oper);
num.push(res);
if(ch=='-'){
isNegative++;
ch='+';
}
cc.push(ch);
} else {
if(ch=='-'){
isNegative++;
ch='+';
}
cc.push(ch);
}
} else {//如果字符栈为空
if(num.isEmpty()&&ch=='-'){//如果数字栈也为空,说明是开头加的字符表示正负
isNegative++;
count++;//这里不++,例如‘-12-2*2’就会出错count先来这个if判断count就等于-1了
}else if (ch=='-'){//如果字符栈为空并且遍历的字符为负数
ch='+';
isNegative++;
cc.push(ch);
}else{//如果字符栈为空并且遍历的字符不是负数
cc.push(ch);
}
}
} else {//如果是数字//
count++;
if(count>=2){//如果大于两位
String n = String.valueOf(ch);
Integer i = new Integer(n);
int a=num.pop();
if(a>=0){//大于两位数,并且数字栈前一个数大于零
a=(a*10)+i;
num.push(a);
count--;
}else{//大于两位数,并且数字栈前一个数小于零
a=(a*10)-i;
num.push(a);
count--;
}
}else{//如果是一位数
//char-->String-->Integer-->int
String n = String.valueOf(ch);
Integer i = new Integer(n);
if(isNegative==1){//如果这个一位数字前面一位是负号
// System.out.println("如果是数字,并且前面是负号,此时存到数字栈的数为:"+(-i));
num.push(-i);
isNegative--;
}else{//如果这个一位数字前面一位是除了负号的符号
// System.out.println("如果是数字,此时存到数字栈的数为:"+i);
num.push(i);
}
}
}
}
// num.showStack();
// cc.showStack();
while (true) {//处理栈中剩下的数
if (cc.isEmpty()) {//如果字符栈为空说明栈处理完毕
break;
}
num1 = num.pop();
num2 = num.pop();
oper = cc.pop();
res = cc.cal(num1, num2, oper);
num.push(res);
}
System.out.println("表达式'" + ex + "'的最终结果是:" + num.peek() + ",res=" + res);
}
}
class NumStack {//模拟数字栈
private int maxSize;
private int[] Stack;
private int top = -1;
public NumStack(int maxSize) {
this.maxSize = maxSize;
Stack = new int[maxSize];
}
public boolean isFull() {
return top == maxSize - 1;
}
public boolean isEmpty() {
return top == -1;
}
public void push(int num) {
if (isFull()) {
System.out.println("数字栈满!存入失败");
return;
}
top++;
Stack[top] = num;
}
public int pop() {
if (isEmpty()) {
// throw new RuntimeException("数字栈空!!!");
return -1;
}
int val = Stack[top];
top--;
return val;
}
//返回当前栈顶的值,但没有从栈中取出
public int peek() {
return Stack[top];
}
public void showStack(){
for(int i=top;i>=0;i--){
System.out.println("Stack["+i+"]"+Stack[i]);
}
}
}
class CharStack {//模拟字符栈
private int maxSize;
private char[] Stack;
private int top = -1;
public CharStack(int maxSize) {
this.maxSize = maxSize;
Stack = new char[maxSize];
}
public boolean isFull() {
return top == maxSize - 1;
}
public boolean isEmpty() {
return top == -1;
}
public void push(char num) {
if (isFull()) {
System.out.println("字符栈栈满!!!");
return;
}
top++;
Stack[top] = num;
}
public char pop() {
if (isEmpty()) {
throw new RuntimeException("字符栈栈空!!!");
}
char val = Stack[top];
top--;
return val;
}
//返回运算符的优先级
// 优先级用数字表示,数字越大优先级越高
public int priority(char oper) {
String oper2 = String.valueOf(oper);
if (oper2.equals("*") || oper2.equals("/")) {
return 1;
} else if (oper2.equals("+") || oper2.equals("-")) {
return 0;
} else {
System.out.println("无法识别优先度!");
return -1;//目前只能识别+、-、*、/
}
}
//判断是不是一个运算符
public boolean isOper(char a) {
String oper = String.valueOf(a);
return oper.equals("+") || oper.equals("-") || oper.equals("*") || oper.equals("/");
}
//计算方法
public int cal(int num1, int num2, char oper) {
int sum = 0;
switch (oper) {
case '+':
sum = num1 + num2;
break;
case '-':
sum = num2 - num1;//注意顺序
break;
case '*':
sum = num1 * num2;
break;
case '/':
sum = num2 / num1;
}
return sum;
}
//返回当前栈顶的值,但没有从栈中取出
public char peek() {
return Stack[top];
}
public void showStack(){
for(int i=top;i>=0;i--){
System.out.println("Stack["+i+"]"+Stack[i]);
}
}
}
待完成:
目前无法计算加括号的表达式
2022.1.26改进:
【JAVA】逆波兰综合计算器
初学数据结构,如果有更好的修改意见请在评论区留言