实现了整数类型的加减乘除
说明:本栈用的是顺序表来存储数据,而顺序表用的是Int数组实现存储的,故没能实现小数的运算,除法运算不能很好实现,小括号也尚未实现
用到了这几个类:顺序表类、栈接口、顺序栈类、计算器类、主类
先看运行结果:
这里是算法原理图:
1. 顺序表类:
package Class.LinearList;
public class LinearList {
public int length = 0;
private int[] arr;
private static final int MIN_CAPACITY = 3;
// 构造方法一
public LinearList(int length) {
if (length >= MIN_CAPACITY) {
arr = new int[length];
} else {
System.out.println("要求线性表最小长度为3!");
}
}
// 构造方法二
public LinearList() {
this(MIN_CAPACITY);
}
// 构造方法三
public LinearList(int []arr) {
if(arr.length <= MIN_CAPACITY) {
throw new RuntimeException("队列长度过小!");
}
this.arr = arr;
length = arr.length;
}
//判断线性表是否为空
public boolean isEmpty() {
return length == 0;
}
// 判断线性表是否为满
public boolean isFull() {
return length == arr.length;
}
// 返回线性表长度
public int size() {
return length;
}
// 返回首个与key相等的元素的索引,查找不成功,返回null(这里是0)
public int keySearch(int key) {
if (isEmpty()) {
throw new RuntimeException("线性表为空!");
}
for (int i = 0; i < length; i++) {
if (arr[i] == key) {
return i;
}
}
System.out.println("线性表中没有该元素");
return 0;
}
// 删除首个与key相等的元素的
public void keyRemove(int key) {
if (isEmpty()) {
System.out.println("线性表为空!");
return;
}
for (int i = 0; i < length; i++) {
if (arr[i] == key) {
arr[i] = 0;
length--;
return;
}
}
System.out.println("线性表中没有该元素");
}
// 插入value,作为第n个元素
public void insert(int value, int n) {
if (isFull()) {
System.out.println("线性表已满");
return;
}
// 插入位置
if (n >= 1 && n <= length + 1) {
for (int i = length; i >= n; i--) {
arr[i] = arr[i - 1];
}
arr[n - 1] = value;
} else if (n > length + 1) {
System.out.println("插入位置过大,自动插入到尾部");
this.insert(value, length + 1);
} else if (n < 1) {
System.out.println("插入位置过小,自动插入到头部");
this.insert(value, 1);
}
length++;
}
// 在尾部插入value元素
public void tailInsert(int value) {
this.insert(value, length + 1);
}
// 删除第n个元素
public int remove(int n) {
if (isEmpty()) {
throw new RuntimeException("线性表为空!");
}
if (n >= 1 && n <= length) {
int temp = arr[n - 1];
for (int i = n - 1; i <= length - 2; i++) {
arr[i] = arr[i + 1];
}
arr[length - 1] = 0;
length--;
return temp;
} else {
throw new RuntimeException("删除位置有误");
}
}
// 顺序栈需求--->删除最后的元素(栈的顶部)并返回
public int tailPop() {
int tail = remove(length);
return tail;
}
// 设置第n个元素为value
public void setValue(int value, int n) {
if (isEmpty()) {
System.out.println("当前线性表为空");
}
if (n > length || n < 1) {
System.out.println("访问越界");
return;
} else {
arr[n - 1] = value;
}
}
//
public void showInfo() {
for (int i = 0; i < length; i++) {
System.out.print(arr[i] + "\t");
}
System.out.println("");
}
//
public int getInt(int index) {
return arr[index];
}
}
2. 抽象栈类(因为栈也能链式存储,不过这里实现的是顺序栈):
package Class.Stack;
public interface Stack {
public abstract boolean isEmpty();
public abstract void push(int num); // 入栈
public abstract int pop(); // 出栈, 并得到该元素
public abstract int peek(); // 返回顶端元素
}
3. 顺序栈类:
package Class.Stack.SeqStack;
import Class.LinearList.LinearList;
import Class.Stack.Stack;
// 顺序栈, 即用顺序表存储元素, 使用前面顺序表中编好的方法.
public class SeqStack implements Stack {
private LinearList linearList;
public SeqStack(LinearList linearList) {
this.linearList = linearList;
}
// 栈是否为空-->顺序表是否为空
@Override
public boolean isEmpty() {
return linearList.isEmpty();
}
// 入栈--->往顺序表尾端插入数据
@Override
public void push(int num) {
linearList.tailInsert(num);
}
// 出栈--->删除顺序表尾端元素并返回
@Override
public int pop() {
return linearList.tailPop();
}
// 查看顶端元素--->查看顺序表尾端元素
@Override
public int peek() {
return linearList.getInt(linearList.length - 1);
}
public int length() {
return linearList.size();
}
}
4. 计算器类
package Class.Stack.SeqStack;
import Class.LinearList.LinearList;
public class Calculator {
// v1.0 支持操作符: + - * / 只支持int类型计算,原因是用的int数组来存储的数据
// 并且除法运算过程中会产生较大误差, int类型/int类型导致, 尽量避免除法运算
// 返回运算符优先级 0 --> +和- 1 ---> *和/
// 从栈pop出来的数字和运算符为int类型(这个栈用线性表存储数据)
public int priority(int ch) {
if (ch == '+' || ch == '-') {
return 0;
} else {
return 1;
}
}
// 判断类型: 数字或是运算符
public boolean isOpera(int ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
public int getResult(int before, int behind, int opera) {
switch (opera) {
case '+':
return before + behind;
case '-':
return before - behind;
case '*':
return before * behind;
case '/':
return before / behind;
default:
return 0;
}
}
public int calculate(String expression) {
char ch; // 依次获取的每一个字符
int index = 0; // 用于记录当前字符串的遍历位置
int before; // 算数表达式中的前面的数 1*2, 指的是 1
int behind; // 后面的数
int opera; // 运算符栈弹出的运算符
int result; // 每次运算后的结果
int finalResult; // 最终结果
SeqStack numStack = new SeqStack(new LinearList(10)); // 数字栈,容量设置为10
SeqStack operaStack = new SeqStack(new LinearList(10)); // 运算符栈, 容量设置为10
while (true) {
ch = expression.substring(index, index + 1).charAt(0);
// 应该判断 ch 类型
if (this.isOpera(ch)) { // 为运算符
// 判断运算符栈是否为空
if (operaStack.isEmpty()) {
operaStack.push(ch);
} else {
// 如果该运算符优先级小于等于栈顶元素
// 1. 从数字栈弹出两个整数,从符号栈弹出运算符
// 2. 把运算结果放到数字栈中
// 3. 把符号放到符号栈
// 如果该运算符优先级大于栈顶元素, 则直接入运算符栈
if (this.priority(ch) <= this.priority(operaStack.peek())) {
behind = numStack.pop(); // 先弹出来的是算数表达式后面的数 1*2,弹出的是2
before = numStack.pop(); // 后弹出来的是算数表达式前面的数
opera = operaStack.pop();
result = this.getResult(before, behind, opera);
numStack.push(result);
operaStack.push(ch);
} else {
operaStack.push(ch);
}
}
} else { // 为数值类型,直接放入数字栈
numStack.push(ch - 48); // '1'对应的int值为49, 应该减去48, 然后存入数字栈
}
index++;
if (index == expression.length()) {
break;
}
}
// 遍历运算符后对符号栈和数字栈剩余元素进行运算
while (true){
behind = numStack.pop(); // 先弹出来的是算数表达式后面的数 1*2,弹出的是2
before = numStack.pop(); // 后弹出来的是算数表达式前面的数
opera = operaStack.pop();
result = this.getResult(before, behind, opera);
numStack.push(result);
if(numStack.length() == 1) {
break;
}
}
return numStack.peek();
}
}
5. 主类
package Class.Stack.SeqStack;
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
int result1 = calculator.calculate("1+2*2+2*2");
System.out.println(result1);
int result2 = calculator.calculate("2*3+1");
System.out.println(result2);
int result3 = calculator.calculate("4/2+1");
System.out.println(result3);
}
}