栈实现综合计算器(中缀表达式)
栈的学习目标
1. 栈的介绍以及特点
2. 栈的应用
3. 代码实现案例
4. 分析案例难点
一,栈的介绍以及特点
栈是一个特殊的线性表,限定只能在尾部(栈顶)进行插入和删除,可以用数组模拟也可以用链表模拟,特点是先进后出,第一个入栈的元素放到了栈底,第一个出去的元素称为栈顶。
二,栈的应用场景
比如逆序打印队列或者链表都可以利用栈的特点实现,这次我的案例是计算一个表达式的值,利用栈进行存储数据。
三,代码实现
计算:2*30/5-2的值
package com.atxiaopeng.stack;
public class StackDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//计算3*3+5-2
Stack numStack = new Stack(10);//数字栈
Stack opersStack = new Stack(10);//符号栈
int index = 0;
int num1= 0;
int num2 = 0;
int oper = 0;//运算符
String keep = "";//组合新的字符串
String string = "2*30/5-2";//要计算的表达式,最后取的是整型,不考虑浮点数
while (index < string.length()) {
char ch = string.substring(index, index+1).charAt(0);//截取单个字符,注意这是前开后闭截取字符串
if (ch>='0'&& ch<='9') {
keep = keep +ch;//重新组合字符串,就是为了解决多位数的运算
if (index == string.length()-1) {
numStack.pushStack(Integer.parseInt(keep));
} else {
//判断是否下个字符为运算符,假如就可以进栈了
if(opersStack.isOper(string.substring(index+1,index+2).charAt(0))) {
numStack.pushStack(Integer.parseInt(keep));
keep = "";
}
}
}else if (opersStack.isOper(ch)) {
if (opersStack.isEmpty()) {
opersStack.pushStack(ch);
}else {
//假如当前运算符的级别低于栈顶的运算级别,这时候就从数字栈中取出来两个数字,把符号栈中的栈顶元素取出运算
if (opersStack.priority(ch) <= opersStack.priority(opersStack.peek())) {
num1 = numStack.pop();
num2 = numStack.pop();
oper = opersStack.pop();
numStack.pushStack(opersStack.cal(num1, num2, oper));
opersStack.pushStack(ch);//然后再把当前运算符号进占
}else {
opersStack.pushStack(ch);
}
}
}else {
System.out.println("表达式内部存在错误字符!");
return;
}
index++;
}
//然后就依次取出运算既可以
while (true) {
if (opersStack.isEmpty()) {
break;
}
num1 = numStack.pop();
num2 = numStack.pop();
oper = opersStack.pop();
numStack.pushStack(opersStack.cal(num1, num2, oper));
}
System.out.println(numStack.pop());
numStack.showStack();
opersStack.showStack();
}
}
class Stack{
int top = -1;
int maxsize ;
int stackarr[];
public Stack(int max) {
this.maxsize = max;
stackarr = new int[max];
}
public boolean isEmpty () {
return top == -1;
}
public boolean isFull() {
return top == maxsize-1;
}
public void pushStack(int a) {
if (isFull()) {
System.out.println("栈已经满了!");
return;
}
top++;
stackarr[top] = a;
}
//查看栈顶元素,并不是出栈
public int peek() {
return stackarr[top];
}
public int pop() {
if (isEmpty()) {
return 0;
}
return stackarr[top--];
}
public void showStack() {
if (isEmpty()) {
System.out.println("栈为空!");
return;
}
for (int i = top; i >= 0; i--) {
System.out.printf("栈内的元素有:%d \n", stackarr[i]);
}
}
//比较优先级
public int priority(int oper) {
if (oper == '*'||oper =='/') {
return 1;
}else if (oper =='+'||oper == '-') {
return 0;
}else {
return -1;
}
}
//判断是否为运算符号
public boolean isOper(char ch) {
return ch == '+'||ch =='-'||ch =='*'||ch =='/';
}
//计算方法
public int cal(int num1,int num2,int oper) {
int res = 0;
switch (oper) {
case '+': res =num1+num2;
break;
case '-': res =num2-num1;
break;
case '*': res =num1*num2;
break;
case '/': res =num2/num1;
break;
default:
break;
}
return res;
}
}
四,代码难点分析
- 搞清楚运算的优先级别,先计算谁后计算谁,整个代码的核心就是先计算谁和谁,不然结果就会出现错误。
- 而且要考虑到多位数运算的情况。思路就是你用一个string接收每次读取的字符,判断下一位是符号还是数字,如果是数字就接着给string,如果是字符string就可以入栈了,注意要判断一下,不要让数组下标越界。
- 如果操作符号的优先级别小于(优先级别自己可以设置)如果当前优先级别小于或等于符号栈中的栈顶元素的优先级,则从数栈中取出两个数,并把符号栈的栈顶元素取出进行计算,结果入数栈,并且当前操作符入符号栈。
- 而且操作数不要搞反了。。。。
共同学习,一起进步!