实现分析
栈是我们计算机中的一种数据结构,它有着先进后出的数据特性。四则运算表达式实现的方式有多种,我们先用栈的数据结构来实现这个算法,在Java中是没有直接的栈结构的,所以要实现此算法,我们的工作有两步:
- 用Java常见的数据类型设计stack类,并根据算法实现的需求设计合理的工具方法
- 理清实现思路用代码表述出来
在这里我们的栈用数据来模拟实现,因为我们是用数组模拟实现的所以我们栈的大小一定是固定的,在我们存取数据的时候应该判断当前栈是否已经满了或是是否里面没有数据以避免数组访问越界,我们对数据的存取需要两个方法。这四个方法可以说是我们栈的基础方法。结合我们算法的实现还需要:判断是否为操作符、操作符优先级的比较、查看栈顶元素、传进操作数操作符的计算。
算法流程图
Java代码实现
package stack;
/**
* @description:
* @function: 通过数组来模拟实现一个栈
* @author: Liu Menglei
* @Date: 2020/8/20 0020 21:48
*/
public class Caculator{
public static void main(String[] args) {
//设置表达式
String expression = "7*2*2-5+1-5+3-4";
// String expression = "(5*(4+4-3)/5+6)-6*(5+2-4)";
//创建数栈、符号栈
StackArray numStack = new StackArray(10);
StackArray operStack = new StackArray(10);
//定义需要的相关变量
int index = 0;
int num1 = 0;
int num2 = 0;
int oper = 0;
int res =0;
char ch = ' ';//将每次扫描到的保存到ch
String keepNum = "";//用来扫描多位数
//使用while来扫描expression
while(true){
//依次得到expression的每个字符
ch = expression.substring(index,index+1).charAt(0);
if (operStack.isOper(ch)){//当前是运算符
//判断当前的栈是否为空
if(operStack.isEmpty()){//当前栈为空直接放入
operStack.push(ch);
}else{//当前的操作符栈中有操作符
if(ch=='('){
operStack.push(ch);
}else if(ch==')'){
while (!(operStack.peek()=='(')){
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
numStack.push(numStack.cal(num1,num2,oper));
}
operStack.pop();
}else {
if(operStack.priority(ch)<=operStack.priority(operStack.peek())){
//如果新读取的操作符的优先级小于等于当前栈顶操作符的优先级那么我们需要从操作数
//栈中弹出两个操作数进行运算
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
numStack.push(numStack.cal(num1,num2,oper));
operStack.push(ch);
}else{
operStack.push(ch);
}
}
}
}else{//当前的是数字
//对多位数的处理
keepNum += ch;
if (index == expression.length()-1){
//如果ch已经是我们expression中的最后一位那么我们就直接入栈
numStack.push(Integer.parseInt(keepNum));
}else{//当前的运算符不是expression的最后一位
if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){//如果后一位是运算符,则入栈
numStack.push(Integer.parseInt(keepNum));
keepNum="";
}
}
}
//让index+1,并判断是否扫描到了expression最后
index ++;
if(index==expression.length()){
break;
}
}
while (true){
if(operStack.isEmpty()){
//当我们的符号栈为空的时候则计算到最后的结果,数栈中只有一个结果那就是我们的结果
break;
}
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1,num2,oper);
numStack.push(res);
}
int resUltimately = numStack.pop();
System.out.printf("表达式%s=%d",expression,resUltimately);
}
}
class StackArray {
private int maxCapacity;
private int[] stackArrays;
private int stackTop = -1;
public StackArray (int maxCapacity){
/**
*@description: 有参构造函数,用来进行一些初始化
*@params: 栈的最大存储容量
*/
this.maxCapacity = maxCapacity;
this.stackArrays = new int[maxCapacity];
}
public boolean isFull (){
/**
*@description: 栈是否已经满了
*@returns: 如果已经满了返回true,没有满的话返回false
*/
return stackTop == maxCapacity-1;
}
public boolean isEmpty (){
/**
*@description: 判断当前的栈是否为空
*@returns: 如果是空的话就返回true,否则返回false
*/
return stackTop==-1;
}
public void push(int element){
if(isFull()){
System.out.println("栈满");
}
stackTop ++;
stackArrays[stackTop] = element;
}
public int pop(){
if (isEmpty()){
throw new RuntimeException("现在栈为空");
}
return stackArrays[stackTop--];
}
public int peek(){
return stackArrays[stackTop];
}
public void list(){
if(isEmpty()){
System.out.println("栈空,没有数据");
}
for (int i = stackTop; i >=0 ; i--) {
System.out.printf("stackArrays[%d]=%d\n",i,stackArrays[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 == '/'||val=='('||val==')';
}
//计算方法
public int cal(int num1, int num2, int oper) {
int res = 0; // res 用于存放计算的结果
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;
}
}
这个算法的实现是很简单的,关键是要理清思维,弄清处理逻辑,朋友们加油奥利给!