栈(stack)
- 栈是一个先入后出的有序列表。
- 栈变化的一端是栈顶,不变的一端是栈底。
栈的实现
定义一个top来表示栈顶,初始化为-1
入栈:当有数据入栈,top++,stack[top]=data
出栈:value=stack[top],top- -
综合计算器的实现
计算器设计思路(含小括号)
- 先定义两个数组栈。一个用于存储数字,一个用于存储运算符号
- 在定义一个index用于读取传进来的算式
- 遇到数字,将其传入数字栈
- 遇到运算符号向符号栈存入,如果符号栈中没有符号就直接入栈;当遇见左括号‘(’时,直接入栈;当遇见右括号’)'时需要将括号中的算式全部运算完毕,直到遇见左括号,停止运算,将左括号出栈;如果将要入栈的符号优先级大于栈顶的符号直接入栈;如果将要入栈的符号优先级小于或等于栈顶符号,先出栈两个数字,先用要入栈的符号进行运算,将结果入数字栈。
- 当读完运算式,将栈中剩余的数字进行依次运算
- 运算规则:先出栈两个数字,再出栈一个符号,用后出栈的数字对先出栈的数字进行运算,将结果入数字栈
代码实现
package Stack;
/**
* 含括号多位加减乘除计算器
* 运用栈
*/
public class ArrayStackDemo {
public static void main(String[] args) {
Calculator cal = new Calculator();
System.out.println(cal.start("((2+3*2)+1*5)-6/2="));
}
}
- 计算器类实现
/**
* 计算器类(含括号,多位运算)
*/
class Calculator {
//计算器运行入口,传入算式字符串(需要结尾带等号)
public int start(String equation) {
Calculator cal = new Calculator();
char ch;//用于暂时存放从算式中取出的字符
int index = 0;//用于标记读取到算式的哪个字符了
String keepNum = "";//用于组成多位数
ArrayStack numStack = new ArrayStack(999);//数字栈
ArrayStack operStack = new ArrayStack(999);//符号栈
//循环进行算式的拆分读取
while (true) {
//读取一个字符
ch = equation.substring(index, index + 1).charAt(0);
//先判断读入的是数字还是字符
if (!cal.isOperation(ch)) {
//传入的为数字
//对其进行多位数拼接
keepNum += ch;
//当下一位是运算符号的时候
if (cal.isOperation(equation.substring(index + 1, index + 2).charAt(0))) {
//将数字入数字栈
numStack.push(Integer.parseInt(keepNum));
//格式化keepNum
keepNum = "";
}
} else if (ch == '=') //当读取到等号时停止读取
{
break;
} else {
//传入的为运算符号
//先判断是否为左括号
if (ch == '(') {
//如果为左括号直接入符号栈
operStack.push((int) ch);
} else if (ch == ')')//判断是不是右括号
{
//如果是右括号需要将括号中的多有运算结束,直到遇见左括号
while (true) {
//当遇见左括号,将左括号出栈,结束括号内的运算
if ((char) operStack.showTop() == '(') {
operStack.pop();
break;
} else {
//循环进行运算,结果入栈,直到遇到括号
numStack.push(cal.count(numStack, operStack));
}
}
} else {
//为运算符号
//先判断栈内是否有符号
if (operStack.isEmpty()) {
//栈内为空,直接入符号栈
operStack.push((int) ch);
} else {
//栈不为空,判断是否需要进行出栈运算
if (cal.comparePriority(ch, operStack)) {
//如果优先级大于栈顶符号,直接入栈
operStack.push(ch);
} else {
//如果优先级小于等于栈顶优先级,出栈两个数字,一个运算符进行运算
int result = cal.count(numStack, operStack);//获得计算结果
//将计算结果入数字栈,当前符号入符号栈
numStack.push(result);
operStack.push((int) ch);
}
}
}
}
index++;
}
//所有的算式都拆分完成了,运算栈中剩下的数字
while (true) {
//判断符号栈是否为空,当符号栈空则表示运算结束,返回结果
if (!operStack.isEmpty()) {
//不为空,继续进行计算
numStack.push(cal.count(numStack, operStack));
} else {
//栈空,结束运算,返回结果
return numStack.pop();
}
}
}
//判断是不是运算符号(加,减,乘,除,括号,等号)
public boolean isOperation(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' || ch == '=';
}
//对运算符号进行优先级分类
//加减=1 乘除=2 左括号=0 右括号=3 等号=-1
public int classifyOperation(char ch) {
if (ch == '+' || ch == '-') {
return 1;
} else if (ch == '*' || ch == '/') {
return 2;
} else if (ch == '(') {
return 0;
} else if (ch == ')') {
return 3;
} else {
return -1;
}
}
//对比符号的优先级,ch为读取的当前运算符,operStack为当前符号栈
//返回正确为当前符号优先级大于栈顶元素优先级;错误为当前符号优先级小于等于栈顶元素优先级;
public boolean comparePriority(char ch, ArrayStack operStack) {
Calculator cal = new Calculator();
//获取当前栈顶运算符号
char chpop = (char) operStack.showTop();
//获取栈顶元素优先级
int priority1 = cal.classifyOperation(chpop);
//获取当前符号优先级
int priority2 = cal.classifyOperation(ch);
if (priority1 < priority2) {
//正确为当前符号优先级大于栈顶元素优先级
return true;
} else {
//错误为当前符号优先级小于等于栈顶元素优先级
return false;
}
}
//从数字栈和符号栈自动出栈进行运算
//num1是先出栈的数字 num2是后出栈的数字 oper是运算符号 numStack是数字栈 operStack是符号栈
public int count(ArrayStack numStack, ArrayStack operStack) {
int num1 = numStack.pop();
int num2 = numStack.pop();
char oper = (char) operStack.pop();
switch (oper) {
case '+':
return num2 + num1;
case '-':
return num2 - num1;
case '*':
return num2 * num1;
case '/':
return num2 / num1;
default:
return 999999999;
}
}
}
- 栈类实现
/**
* 栈类
*/
class ArrayStack {
private int stack[];
private int top;
private int max;
//初始化栈
public ArrayStack(int max) {
stack = new int[max];
top = -1;
this.max = max;
}
//判满
public boolean isFull() {
return top == max - 1;
}
//判空
public boolean isEmpty() {
return top == -1;
}
//入栈
public void push(int data) {
//判满
if (isFull()) {
System.out.println("栈满,无法入栈");
return;
}
top++;
stack[top] = data;
}
//出栈
public int pop() {
//判空
if (isEmpty()) {
System.out.println("栈空");
new RuntimeException("栈空");
}
int value = stack[top];
top--;
return value;
}
//显示栈
public void showStack() {
//从栈顶显示到栈底
for (int i = top; i >= 0; i--) {
System.out.println(stack[i]);
}
}
//返回栈顶(栈顶不出栈)
public int showTop() {
return stack[top];
}
}
``