思路图解
例子分析
代码实现
/**
* 通过数组来模拟栈
*/
class ArrayStack{
private int size;//栈的大小
private int[] stack;//数组模拟栈
private int top;//栈顶
/**
* 构造方法 用于初始化栈
* @param size
*/
public ArrayStack(int size) {
this.size = size;
this.stack = new int[size];
this.top = 0;
}
/**
* 判断是否满栈
* @return
*/
public boolean isFull(){
return size == top;
}
/**
* 判断是否空栈
* @return
*/
public boolean isEmpty(){
return top == 0;
}
/**
* 入栈
* @param data
*/
public void push(int data){
//判断是否满栈
if(isFull()){
System.out.println("已满,无法入栈");
return;
}
stack[top] = data;
top++;
}
/**
* 出栈
*/
public int pop(){
if (isEmpty()){
throw new RuntimeException("空栈,无法弹出");
}
top--;
return stack[top];
}
public int peek(){
int temp = top -1;
return stack[temp];
}
/**
* 遍历栈中数据
*/
public void showStack(){
if(isEmpty()){
System.out.println("空栈 无法打印");
return;
}
for (int i= top-1; i>=0; i--){
System.out.println(stack[i]);
}
}
}
/**
* 计算器
*/
public class Calculator {
public static void main(String[] args) {
//定义需要计算的表达式字符串
String expression = "3+2*6-2";
//创建栈
ArrayStack numStack = new ArrayStack(10);//数字栈
ArrayStack operStack = new ArrayStack(10);//符号栈
int index = 0;//用于解析表达式
while (true){
//获取表达式的每个字符
char ch = expression.substring(index, index + 1).charAt(0);
if(isOpen(ch)){//如果是符号
if(operStack.isEmpty()){//如果符号栈是空的,符号直接入符号栈
operStack.push(ch);
}else{//符号栈不为空
//判断当前符号和符号栈栈顶的符号的优先级大小
if (isPriority(ch) > isPriority((char) operStack.peek()) ){//当前符号优先级大
operStack.push(ch);//符号栈入符号栈
}else {//当前符号优先级小
//从数字栈出栈两个数字
int num1 = numStack.pop();
int num2 = numStack.pop();
//从符号栈出栈一个符号
int oper = operStack.pop();
//计算结果
int sum = cal(num1,num2,oper);
//结果入数字栈
numStack.push(sum);
//当前符号符符号栈
operStack.push(ch);
}
}
}else{//如果是数字
//入数字栈
numStack.push(ch-48);
}
index++;
//当表达式遍历完毕 退出循环
if(index >= expression.length()){
break;
}
}
//表达式解析完毕,计算栈中数据
while (true){
//判断符号栈是否为空
if (operStack.isEmpty()){//为空表明计算完毕
break;
}
int num1 = numStack.pop();
int num2 = numStack.pop();
int oper = operStack.pop();
int sum = cal(num1,num2,oper);
numStack.push(sum);//入栈
}
//将数栈的最后数,pop出,就是结果
int result = numStack.pop();
System.out.printf("表达式 %s = %d", expression, result);
}
/**
* 判断当前字符是不是操作符
* @param ch true 是操作符
* @return
*/
private static boolean isOpen(char ch){
return ch == '+' || ch == '-' || ch == '*' || ch == '/' ;
}
/**
* 判断传入的符号的优先级
* @param oper
* @return
*/
private static int isPriority(char oper){
if(oper == '*' || oper == '/'){
return 1;
}
if(oper == '+' || oper == '-'){
return 0;
}
return -1;
}
/**
* 两个数的加减乘除运算
* @param num1
* @param num2
* @param oper 符号
* @return
*/
private static 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;
}
}
此时计算机实现完毕,但是可以发现一个问题,只能计算10以内(不包括10)的加减乘除,并且不能有小括号。如有疑问或者指教,请留言方便交流。
解决多位数问题
只需要将数字入数字栈的地方做出修改即可。
numStack.push(ch-48);
修改为:
//判断多位数的操作
keepNum = keepNum + ch;
//如果当前字符ch是表达式的最后一位,则直接入栈
if (index == expression.length()-1){
numStack.push(Integer.parseInt(keepNum));
}else {//不是表达式的最后一个字符
//判断下一个字符是不是数字,如果不是数字,则入栈
if (isOper(expression.substring(index + 1, index + 2).charAt(0))) {
numStack.push(Integer.parseInt(keepNum));
keepNum = "";
}
}
解决小括号问题,详情参考后缀表大四。