1.逆波兰计算器
我们完成一个逆波兰计算器,要求完成如下任务:
1)输入一个逆波兰表达式(后缀表达式),使用栈(Stack),计算其结果
2)支持小括号和多位数整数,因为这里我们主要讲的是数据结构,因此计算器进行简化,只支持对整数的计算。
3)思路分析
例如:(3+4)×5-6对应的后缀表达式就是3 4 + 5 × 6 -,针对后缀表达式求值步骤如下:
1.从左至右扫描,将3和4压入堆栈;
2.遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
3.将5入栈;
4.接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;5.将6入栈;
6.最后是-运算符,计算出35-6的值,即29,由此得出最终结果
public class PolandNotation {
public static void main(String[] args) {
String expression = "30 4 + 5 * 6 -";
List<String> list = formatString(expression);
int calculator = calculator(list);
System.out.println("计算结果是"+calculator);
}
//格式化后缀表达式
public static List<String> formatString(String expression){
//把表达式按照空格划分开 格式化
String[] s = expression.split(" ");
//把格式化后的表达式放到数组中
ArrayList<String> list = new ArrayList<>();
//把所有的数据添加到数组中
list.addAll(Arrays.asList(s));
return list;
}
//创建一个方法 计算
public static int calculator(List<String> ls){
Stack<String> calStack = new Stack<>();
for (String item : ls) {
//这里匹配多位数字
if (item.matches("\\d+")){
calStack.push(item);
}else {
//从栈中取出两位数字
int num1 = Integer.parseInt(calStack.pop());
int num2 = Integer.parseInt(calStack.pop());
//结果
int res;
//匹配加减乘除
if (item.equals("+")){
res = num1 + num2;
}else if (item.equals("-")){
res = num2 - num1;
}else if (item.equals("*")){
res = num1 * num2;
}else if (item.equals("/")){
res = num2 * num1;
}else {
break;
}
calStack.push(""+res);
}
}
return Integer.parseInt(calStack.pop());
}
}
2.中缀表达式转为后缀表达式
package stack;
/*
@CreateTime 2021/9/10 11:36
@CreateBy cfk
逆波兰表达式
把中缀表达式转化为后缀表达式
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
public class PolandNotation {
public static void main(String[] args) {
String expression = "1+((2+3)*4)-5";
List<String> strings = toInfixList(expression);
System.out.println("把中缀表达式转化为了集合== "+strings);
System.out.println("把中缀表达式转化为了后缀表达式== "+suffixFormatList(strings));
}
//将中缀表达式转化为后缀表达式
/*
1)初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2)从左至右扫描中缀表达式;
*/
public static List<String> suffixFormatList(List<String> expression){
//创建一个符号栈
Stack<String> curStack = new Stack<>();
//创建一个集合存储中间结果
ArrayList<String> list = new ArrayList<>();
for (String item : expression) {
//3)遇到操作数时,将其压s2;
if (item.matches("\\d+")){
list.add(item);
/*
5)遇到括号时:
(1)如果是左括号“(”,则直接压入s1
(2)如果是右括号“)”,则依次弹出sl栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
*/
}else if (item.equals("(")){
curStack.push(item);
// String expression = "1+((2+3)*4)-5";
}else if (item.equals(")")){
while (!curStack.peek().equals("(")){
list.add(curStack.pop());
}
curStack.pop();
}else {
/*4)遇到运算符时,比较其与s1栈顶运算符的优先级:
1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;*/
while (curStack.size() != 0 && OperatorOrder.getOrder(item)<=OperatorOrder.getOrder(curStack.peek())) {
list.add(curStack.pop());
}
curStack.push(item);
}
}
// 6)重复步骤2至5,直到表达式的最右边
// 7)将s1中剩余的运算符依次弹出并压入 s2
// 8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
while (curStack.size() != 0) {
list.add(curStack.pop());
}
return list;
}
//把中缀表达式转化为一个集合 ArrayList [1,+.(.(,2,+,3,)*.4,).-,5] =》ArrayList [ 1,2,3,+,4,*,+,5,-l
//1+((2+3)×4)-5
public static List<String> toInfixList(String expression){
//创建一个集合存储
List<String> list = new ArrayList<>();
//定位标志
int index = 0;
//定义一个可变字符串 用来处理后面的多位数字
StringBuilder builder = new StringBuilder();
while (index < expression.length()){
//如果表示的数据为符号时 进行以下的处理
if (expression.charAt(index)<48
|| expression.charAt(index)>57){
list.add(expression.charAt(index)+"");
index++;
}else {
//如果数据为数字 并且多位数字进行以下处理
while (index < expression.length() && expression.charAt(index)>=48
&& expression.charAt(index)<=57){
builder.append(expression.charAt(index));
index++;
}
list.add(builder.toString());
builder.setLength(0);
}
}
return list;
}
}
感觉这种算法题不好想,很多靠理解,当自己理清思路之后实现起来就没那么困难了
不要死记硬背!!!