package cn.tedu.stack;
import java.util.Scanner;
/**
* @author keke
* @version 1.0
* @className ArrayStackDemo
* @description
* @time 2023/6/6 23:17
*/
public class ArrayStackDemo {
public static void main(String[] args) {
ArrayStack<Integer> stack = new ArrayStack<>(4);
String key = "";
boolean loop = true;
Scanner scanner = new Scanner(System.in);
while (loop) {
System.out.println("show:表示显示栈");
System.out.println("exit:退出查询");
System.out.println("push:表示添加数据到栈(入栈)");
System.out.println("pop:表示从栈中取出数据(出栈)");
System.out.print("请输入你的选择:");
key = scanner.next();
switch (key) {
case "show":
stack.list();
break;
case "push":
System.out.print("请输入一个数:");
stack.push(scanner.nextInt());
break;
case "pop":
try {
System.out.println("出栈的数据是:" + stack.pop());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case "exit":
scanner.close();
loop = false;
break;
}
}
System.out.println("程序退出");
}
}
class ArrayStack<T> {
private int maxSize;
/**
* 数组模拟栈,数据就放在该数组
*/
private T[] stack;
/**
* 栈顶
*/
private int top = -1;
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
stack = (T[]) new Object[maxSize];
}
public boolean isFull() {
return top == maxSize - 1;
}
public boolean isEmpty() {
return top == -1;
}
public void push(T value) {
if (isFull()) {
System.out.println("栈满");
return;
}
stack[++top] = value;
}
public T pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据");
}
return stack[top--];
}
public void list() {
if (isEmpty()) {
System.out.println("栈空,没有数据");
return;
}
for (int i = top; i >= 0; i--) {
System.out.println("stack[" + i + "]=" + stack[i]);
}
}
}
package cn.tedu.stack;
/**
* @author keke
* @version 1.0
* @className Caculator
* @description
* @time 2023/6/7 22:54
*/
public class Caculator {
public static void main(String[] args) {
String expression = "45+22*6-2";
System.out.println("表达式" + expression + " = " + caculator(expression));
}
private static Integer caculator(String expression) {
ArrayStack2<Integer> numStack = new ArrayStack2<>(10);
ArrayStack2<Character> operStack = new ArrayStack2<>(10);
int index = 0;
int num1 = 0;
int num2 = 0;
int oper = 0;
int res = 0;
char ch = ' ';
String keepNum = "";
// 开始 while 循环扫描 expression
do {
// 依次得到 expression 的每一个字符
ch = expression.substring(index, index + 1).charAt(0);
// 判断 ch 是什么,然后做相应的处理
if (operStack.isOper(ch)) {
// 判断当前符号栈是否为空
if (!operStack.isEmpty()) {
// 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符
// 就需要从数栈中 pop 出两个数,在从符号栈中 pop 出一个符号,进行运算,将得到结果,
// 入数栈,然后将当前的操作符入符号栈
if (operStack.priority(ch) < operStack.priority(operStack.peek())) {
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
// 把运算结果入数栈
numStack.push(res);
// 将当前的操作符入符号栈
operStack.push(ch);
} else {
// 如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈
operStack.push(ch);
}
} else {
// 如果为空直接入符号栈
operStack.push(ch);
}
} else {
// numStack.push(ch - 48);
// 当处理多位数是,不能发现是一个数就立即入栈,可能是多位数
// 在处理数,需要向 expression 的表达式的 index 后在看一位,如果是数就进行扫描,如果是符号才入栈
// 需要定义一个字符串变量,用于拼接
keepNum += ch;
// 如果 ch 是 expression 的最后一位,就直接入栈
if (index == expression.length() - 1) {
numStack.push(Integer.parseInt(keepNum));
} else {
// 判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,则入栈
if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
// 如果后一位是运算符,则入栈
numStack.push(Integer.parseInt(keepNum));
// 清空
keepNum = "";
}
}
}
// 让 index + 1,并判断是否扫描到 expression 最后
index++;
} while (index < expression.length());
// 当表达式扫描完毕,就顺序的从 数栈和符号栈中 pop 出相应的数和符号,并运行.
while (!operStack.isEmpty()) {
// 如果符号栈为空,则计算到最后结果,数栈只有一个数字
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
// 入栈
numStack.push(res);
}
return numStack.pop();
}
}
class ArrayStack2<T> {
private int maxSize;
/**
* 数组模拟栈,数据就放在该数组
*/
private T[] stack;
/**
* 栈顶
*/
private int top = -1;
public ArrayStack2(int maxSize) {
this.maxSize = maxSize;
stack = (T[]) new Object[maxSize];
}
public boolean isFull() {
return top == maxSize - 1;
}
public boolean isEmpty() {
return top == -1;
}
public void push(T value) {
if (isFull()) {
System.out.println("栈满");
return;
}
stack[++top] = value;
}
public T pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据");
}
return stack[top--];
}
public void list() {
if (isEmpty()) {
System.out.println("栈空,没有数据");
return;
}
for (int i = top; i >= 0; i--) {
System.out.println("stack[" + i + "]=" + stack[i]);
}
}
/**
* 返回运算符的优先级,优先级是程序员来确定的,优先级使用数字表示
* 数字越大,则优先级越高
*
* @param oper
* @return
*/
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 == '/';
}
public int cal(int num1, int num2, int oper) {
int res = 0;
switch (oper) {
case '+':
res = num1 + num2;
break;
case '-':
res = num2 - num1;
break;
case '*':
res = num1 * num2;
break;
case '/':
res = num2 / num1;
break;
}
return res;
}
public T peek() {
return stack[top];
}
}
后缀表达式适合计算式进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将中缀表达式转成后缀表达式。
中缀表达式 1 + ( ( 2 + 3 )× 4) - 5 =》 后缀表达式 1 2 3 + 4 * + 5 -
package cn.tedu.stack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
/**
* @author keke
* @version 1.0
* @className PolandNotation
* @description
* @time 2023/6/11 15:22
*/
public class PolandNotation {
public static void main(String[] args) {
// 完成将一个中缀表达式转成后缀表达式的功能
// 1.因为直接对 str 进行操作,不太方便,因此转为中缀表达式对应的 List
// 2.将中缀表达式对应的 List 转为后缀表达式对应的 List
String expression = "1+((2+3)*4)-5";
List<String> infixExpressionList = toInfixExpressionList(expression);
System.out.println("infixExpressionList = " + infixExpressionList);
List<String> parsedSuffixExpressionList = parseSuffixExpressionList(infixExpressionList);
System.out.println("parsedSuffixExpressionList = " + parsedSuffixExpressionList);
System.out.println(expression + "=" + calculate(parsedSuffixExpressionList));
/* // 定义一个逆波兰表达式
// 为了方便,逆波兰表达式的数字和符号使用空格隔开
String subfixExpression = "30 4 + 5 * 6 -";
// 1.先将 "3 4 + 5 * 6 -" 放到 ArrayList
// 2.将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈完成计算
List<String> rpnList = getListString(subfixExpression);
System.out.println(rpnList);
System.out.println(calculate(rpnList)); */
}
/**
* 将一个逆波兰表达式,依次将数据和运算符放入到 ArrayList 中
*
* @param subfixExpression
* @return
*/
public static List<String> getListString(String subfixExpression) {
// 将 suffixExpression 分割
String[] split = subfixExpression.split(" ");
return new ArrayList<>(Arrays.asList(split));
}
/**
* 完成对逆波兰表达式的运算
* 从左至右扫描,将3和4压入堆栈;
* 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
* 将5入栈;
* 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
* 将6入栈;
* 最后是-运算符,计算出35-6的值,即29,由此得出最终结果
* @param ls
* @return
*/
public static int calculate(List<String> ls) {
Stack<String> stack = new Stack<>();
for (String item : ls) {
// 使用正则表达式来取出数
if (item.matches("\\d+")) {
// 入栈
stack.push(item);
} else {
int num2 = Integer.parseInt(stack.pop());
int num1 = Integer.parseInt(stack.pop());
int res = 0;
switch (item) {
case "+":
res = num1 + num2;
break;
case "-":
res = num1 - num2;
break;
case "*":
res = num1 * num2;
break;
case "/":
res = num1 / num2;
break;
default:
throw new RuntimeException("运算符有误");
}
stack.push(String.valueOf(res));
}
}
// 最后留在栈中的数据是运算结果
return Integer.parseInt(stack.pop());
}
/**
* 将中缀表达式转成对应的 List
* @param expression
* @return
*/
public static List<String> toInfixExpressionList(String expression){
List<String> list = new ArrayList<>();
int i = 0;
// 对多位数进行拼接
StringBuilder str = new StringBuilder();
// 每遍历一个字符,就放入到c
char c;
do {
// 如果 c 是一个非数字,加入到 list
if ((c = expression.charAt(i)) < 48 || (c = expression.charAt(i)) > 57) {
list.add(String.valueOf(c));
i++;
} else {
// 置空
str = new StringBuilder();
while (i < expression.length() &&(c = expression.charAt(i)) >= 48 && (c = expression.charAt(i)) <= 57) {
// 拼接
str.append(c);
i++;
}
list.add(str.toString());
}
}while (i < expression.length());
return list;
}
/**
* 将中缀表达式对应的 List 转为后缀表达式对应的 List
* @param list
* @return
*/
public static List<String> parseSuffixExpressionList(List<String> list) {
Stack<String> s1 = new Stack<>();
// 因为 s2 这个栈,在整个转换过程中没有 pop 操作,而且后面还需要逆序输出
List<String> s2 = new ArrayList<>();
for (String item : list) {
// 如果是一个数,加入 s2
if (item.matches("\\d+")) {
s2.add(item);
} else if (item.equals("(")) {
s1.push(item);
} else if (item.equals(")")) {
// 如果是右括号 “)”,则依次弹出 s1 栈顶的运算符,并压入 s2,
// 直到遇到左括号为止,此时将这一对括号丢弃
if (!s1.peek().equals("(")) {
s2.add(s1.pop());
}
// 消除一对小括号
s1.pop();
} else {
//当 item 的优先级小于等于栈顶运算符,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到 (4.1) 与 s1 中新的栈顶运算符相比较
// 缺少一个比较优先级的方法
while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
s2.add(s1.pop());
}
// 还需要加 item 压入栈
s1.push(item);
}
}
// 将 s1 中剩余的运算符依次弹出并加入 s2
while (s1.size() != 0){
s2.add(s1.pop());
}
return s2;
}
}
class Operation {
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
public static int getValue(String operation){
int result = 0;
switch (operation) {
case "+":
result = ADD;
break;
case "-":
result =SUB;
break;
case "*":
result = MUL;
break;
case "/":
result = DIV;
break;
default:
System.out.println("不存在该运算符");
break;
}
return result;
}
}
逆波兰计算器完整版考虑的因素较多,下面给出完整版代码供同学们学习,其基本思路和前面一样,也是使用到:中缀表达式转后缀表达式。
package cn.tedu.stack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
/**
* @author keke
* @version 1.0
* @className ReversePolishMultiCalc
* @description
* @time 2023/6/11 17:21
*/
public class ReversePolishMultiCalc {
/**
* 匹配 + - * / ( ) 运算符
*/
private static final String SYMBOL = "[+\\-*/()]";
private static final String LEFT = "(";
private static final String RIGHT = ")";
private static final String ADD = "+";
private static final String MINUS = "-";
private static final String TIMES = "*";
private static final String DIVISION = "/";
/**
* 加減 + -
*/
private static final int LEVEL_01 = 1;
/**
* 乘除 * /
*/
private static final int LEVEL_02 = 2;
/**
* 括号
*/
private static final int LEVEL_HIGH = Integer.MAX_VALUE;
private static Stack<String> stack = new Stack<>();
private static List<String> data = Collections.synchronizedList(new ArrayList<>());
/**
* 去除所有空白符
*
* @param s
* @return
*/
public static String replaceAllBlank(String s) {
// \\s+ 匹配任何空白字符,包括空格、制表符、换页符等等, 等价于[ \f\n\r\t\v]
return s.replaceAll("\\s+", "");
}
/**
* 判断是不是数字 int double long float
*
* @param s
* @return
*/
public static boolean isNumber(String s) {
Pattern pattern = Pattern.compile("^[-+]?[.\\d]*$");
return pattern.matcher(s).matches();
}
/**
* 判断是不是运算符
*
* @param s
* @return
*/
public static boolean isSymbol(String s) {
return s.matches(SYMBOL);
}
/**
* 匹配运算等级
*
* @param s
* @return
*/
public static int calcLevel(String s) {
if ("+".equals(s) || "-".equals(s)) {
return LEVEL_01;
} else if ("*".equals(s) || "/".equals(s)) {
return LEVEL_02;
}
return LEVEL_HIGH;
}
/**
* 匹配
*
* @param s
*/
public static List<String> doMatch(String s) {
if (s == null || "".equals(s.trim())) {
throw new RuntimeException("data is empty");
}
if (!isNumber(String.valueOf(s.charAt(0)))) {
throw new RuntimeException("data illeagle,start not with a number");
}
s = replaceAllBlank(s);
String each;
int start = 0;
for (int i = 0; i < s.length(); i++) {
if (isSymbol(String.valueOf(s.charAt(i)))) {
each = String.valueOf(s.charAt(i));
// 栈为空,(操作符,或者 操作符优先级大于栈顶优先级 && 操作符优先级不是( )的优先级 及是 ) 不能直接入栈
if (stack.isEmpty() || LEFT.equals(each)
|| ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGH)) {
stack.push(each);
} else if (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {
// 栈非空,操作符优先级小于等于栈顶优先级时出栈入列,直到栈为空,或者遇到了(,最后操作符入栈
while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {
if (calcLevel(stack.peek()) == LEVEL_HIGH) {
break;
}
data.add(stack.pop());
}
stack.push(each);
} else if (RIGHT.equals(each)) {
// ) 操作符,依次出栈入列直到空栈或者遇到了第一个)操作符,此时)出栈
while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())) {
if (LEVEL_HIGH == calcLevel(stack.peek())) {
stack.pop();
break;
}
data.add(stack.pop());
}
}
// 前一个运算符的位置
start = i;
} else if (i == s.length() - 1 || isSymbol(String.valueOf(s.charAt(i + 1)))) {
each = start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1);
if (isNumber(each)) {
data.add(each);
continue;
}
throw new RuntimeException("data not match number");
}
}
// 如果栈里还有元素,此时元素需要依次出栈入列,可以想象栈里剩下栈顶为 /,栈底为 +,应该依次出栈入列,可以直接翻转整个 stack 添加到队列
Collections.reverse(stack);
data.addAll(new ArrayList<>(stack));
System.out.println(data);
return data;
}
/**
* 算出结果
*
* @param list
* @return
*/
public static Double doCalc(List<String> list) {
double d = 0d;
if (list == null || list.isEmpty()) {
return null;
}
if (list.size() == 1) {
System.out.println(list);
d = Double.parseDouble(list.get(0));
return d;
}
ArrayList<String> list1 = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
list1.add(list.get(i));
if (isSymbol(list.get(i))) {
Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i));
list1.remove(i);
list1.remove(i - 1);
list1.set(i - 2, String.valueOf(d1));
list1.addAll(list.subList(i + 1, list.size()));
break;
}
}
doCalc(list1);
return d;
}
/**
* 运算
*
* @param s1
* @param s2
* @param symbol
* @return
*/
public static Double doTheMath(String s1, String s2, String symbol) {
Double result;
switch (symbol) {
case ADD:
result = Double.parseDouble(s1) + Double.parseDouble(s2);
break;
case MINUS:
result = Double.parseDouble(s1) - Double.parseDouble(s2);
break;
case TIMES:
result = Double.parseDouble(s1) * Double.parseDouble(s2);
break;
case DIVISION:
result = Double.parseDouble(s1) / Double.parseDouble(s2);
break;
default:
result = null;
}
return result;
}
public static void main(String[] args) {
// String math = "9+(3-1)*3+10/2";
String math = "12.8 + (2 - 3.55)*4+10/5.0";
doCalc(doMatch(math));
}
}