文章目录
- 前言
- 一、用栈实现综合计算器的思路
- 二、代码实现
- 2.代码中的问题
前言
学习打卡:栈的应用
提示:以下是本篇文章正文内容,下面案例可供参考
一、用栈实现综合计算器的思路
二、代码实现
代码如下(示例):
package DataStructures;
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
//给出一个表达式进行测试
String expression = "700+2*6-4";
//创建两个栈,数栈,符号栈
Stack2 numStack = new Stack2(10);
Stack2 operStack = new Stack2(10);
//定义相关的变量
int index = 0;//用于扫描表达式
int num1 = 0;
int num2 = 0;
int oper = 0;
int res = 0;
char ch = ' ';//将每次扫描得到的char保存到ch
String keepNum = "";//用于拼接多位数
//开始while循环的扫描expression
while(true){
//一次得到expression的每一个字符
ch = expression.substring(index,index+1).charAt(0);//substring返回的是字符串(String)还要转为字符类
//判断ch是什么,做相应的处理
if(operStack.isOper(ch)){//如果是一个运算符的话
//判断当前的符号栈是否为空
if(!operStack.isEmpty()){
//不为空,就判断优先级,如果当前的符号大于栈顶的符号优先级,直接存入
//当前小于或则等于栈顶的(最多只留下一个高级符在栈里),那就先把高级符号给算了,(数栈弹出两个,符号栈弹出一个,计算后结果存入数栈,再把当前符号存入)
if(operStack.priority(ch)<=operStack.priority(operStack.peek())){
//明明方法指定的参数是int类型的,为什么char也行??因为char对应有int的数字(Ascall码)
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1,num2,oper);
//把结果入数栈
numStack.push(res);
//把当前运算符号入栈
operStack.push(ch);//规定char类型的参数是不能接受int的,但是int可以接受char
}else{
//如果栈顶运算符大于当前运算符,直接入栈
operStack.push(ch);
}
}else{
//如果为空直接入栈
operStack.push(ch);
}
}else{//如果是数字直接入栈(但是只能扫描到一位数字不能扫描多位)
//当处理多位数时,不能发现就立即入栈,因为可能是多位
//在扫描时,如果是数字,再后看一位,如果是数就继续扫描,是符号就入数栈
//定义一个变量字符串,用于拼接
keepNum += ch;
//如果ch已经是表达式最后一位了,就直接入栈,后面不用探了
if(index == expression.length()-1){
numStack.push(Integer.parseInt(keepNum));//拼接是字符串要转化成数字
}else{
//numStack.push(ch-48);//对于本来的数字变成char类在Ascall码里面是等于原来的数字加上48的,char在数字上要大一点
//判断下一个字符是不是数字,如果是数字,就继续扫描,是运算符,则入数栈
//看后一位,不是index
if(operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
//如果最后一位是运算符就可以入栈了keepnum="1"或则“123”要转化
numStack.push(Integer.parseInt(keepNum));
//因为要进行下一次拼接,所以要清空keepnum
keepNum = "";//如果是数字的话,不入栈,他会在下一个循环拼接上
}
}
}
//然index+1;并判断是否扫描到最后
index++;
if(index>=expression.length()){//index最小的索引是从0开始,当加到length-1时就已经全部扫完了,再加一的话就是length就停止
break;//退出循环
}
}
//循环过后符号栈里面优先级都是升序的,所以可以按照顺序pop出来进行运算
while(true){
//当符号栈为空时,则计算到最后的结果,数栈中只有一个数字(结果)
if(operStack.isEmpty()){
break;//结束标志:运算符都用完了
}
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1,num2,oper);
//把结果入数栈
numStack.push(res);
}
System.out.printf("表达式%s = %d",expression,numStack.pop());//%s就是字符串,%c那就是字符喽
}
}
class Stack2 {//在主类里定义类用static
private int maxSize;//栈的大小
private int[] stack;//数组,数组模拟栈,数据被存放在数组
private int top = -1;//表示栈顶,初始化为-1
//构造器
public Stack2(int maxSize) {
this.maxSize = maxSize;
stack = new int[maxSize];//数组要有初始化
}
//返回栈顶元素,并不是pop出来
public int peek(){
return stack[top];//栈顶指针没动,就不算pop
}
//栈满
public boolean isFill() {
return top == maxSize - 1;
}
//栈空
public boolean isEmpty() {
return top == -1;
}
//入栈
public void push(int value) {
//先判断是否满了
if (isFill()) {
System.out.println("栈满,无法加入数据");
}
top++;//初始值为-1;要先动
stack[top] = value;
}
//出栈,将栈顶数据返回
public int pop() {
//判断是否为空
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据");
}
int value = stack[top];
top--;//栈顶指针下移了,相当于pop
return value;
}
//显示栈,遍历,从栈顶遍历
public void list() {
//判断是否为空
if (isEmpty()) {
System.out.println("栈空,没有数据");
}
for (int i = top; i >= 0; i--) {
System.out.printf("stack[%d]=%d\n", i, stack[i]);
}
}
//返回运算符的优先级,优先级使用数字表示,数字越大优先级越高
public int priority(int oper){//int可以接受char Ascall码里面有这个字符的对应数字 但是字符串是没有的
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 res = 0;//用于存放计算的结果
switch (oper){
case '+':
res = num1+num2;
//return res;
break;
case '-':
res = num2-num1;//注意顺序,谁在前面
//return res;
break;
case '*':
res = num1*num2;
//return res;
break;
case '/':
res = num2/num1;//后面弹出来的在表达式中是前面的一个位置
//return res;
break;
default:
break;//不规则直接退出
}
return res;//这就减少了代码量重复代码。。。
}
}
2.代码中的问题
- 利用先前就建立的栈原型:出栈,入栈,显示栈顶元素(后根据需求加的)等一些功能,进行实现需求时就可以直接引用里面的相关方法很方便(但还是要打那么多代码。。。麻烦)
- 里面的逻辑关系很杂,一不小心就可能弄错
- index扫描表达式时,对于数字只能扫描一位就入栈了,不满住多位运算,利用字符串拼接,扫到数字时先用空字符串拼接,(先判断此数字是否到达表达式的最后,如果到最后就不用扫,直接入栈)再扫描此数字的下一位,如果是符号就直接转化后入数栈,如果还是数字的话,就不会入栈,等到下一次循环时,就会被keepnum拼接上变成“12”之类的,又会基于这个数字扫描下一个,如果是运算符号,那就转化后入数栈。这样就实现了多位数字的入栈