今天和几个同学正好谈到,就分享一下 SimpleDateFormat具有线程安全问题,在Java8之后,可以使用线程安全的LocalDate、LocalTime、或者LocalDateTime,但是说实话,这个LocalDate比SimpleDateFormat麻烦太多了..但是能写一个工具类来封装一下常用的方法.所以好像也不是那么难搞
?
不吹牛了不吹牛了,说正事
目录
前缀表达式
中缀表达式
后缀表达式
中缀转后缀思路:
代码一:(后缀表达式计算器)
代码二:(中缀表达式计算器)?
前缀表达式
"(3+4)*5-6"如果用前缀表达式来表示,就是"?- * + 3 4 5 6?" 计算前缀表达式:从右到左扫描前缀表达式,遇到数字就push进栈,遇到符号就从栈中pop出栈顶和次顶的元素与该符号做计算(栈顶元素为num1,次顶元素为num2),再把结果值push入栈;如此循环,直到只剩下一个数,即是结果
中缀表达式
"(3+4)*5-6"这种类型就是中缀表达式,虽然我们可以清楚的从中分析出计算逻辑,但是对于计算机来说,还需要判断优先级,所以在计算机计算时,会将中缀表达式转换成其他类型的表达式
后缀表达式
"(3+4)*5-6"如果用后缀表达式来表示,就是" 3 4 + 5 * 6 - " 计算后缀表达式:从左到右扫描后缀表达式,遇到数字就push进栈,遇到符号就从栈中pop出栈顶和次顶的元素与该符号做计算(栈顶元素为num2,次顶元素为num1),再把结果值push入栈;如此循环,直到只剩下一个数,即是结果?
你这个num1和num2是啥东西?换个名字有啥区别呢? -->? "num1 操作符 num2" 这应该能懂了吧,其实就是前缀表达式是把栈顶元素放在前面(作为被减数,被除数这种),后缀表达式把栈顶元素放在后面
有小朋友又要问了:那么,怎么把我们写的中缀表达式转换为后缀表达式呢? 这玩意比较麻烦,涉及到的步骤很多
中缀转后缀思路:
1.初始化两个栈:运算符栈s1与储存中间结果的栈s2 2.从左到右扫描中缀表达式 3.遇到数字时,push进s2 4.遇到运算符X时,先与s1栈顶操作符比较优先级 ? ?①如果s1为空或者栈顶为''("左括号或者X优先级大于栈顶符号优先级 ? ? ? ?push入s1 ? ?②若不满足以上,pop出s1栈顶的操作符,并将其push进s2;? ? ? ? ? 然后回到第4步开头,继续与s1新栈顶元素比较? ? ? ? 5.遇到括号时 ? ?①如果是"("左括号,直接push进s1 ? ?②如果是")"右括号,则一次pop出s1栈顶的运算符,并push进s2,直到遇到"("左括号为止,然后将这一对括号丢弃 6.遍历结束之后,将s1中的操作符依次pop并push进s2 7.pop出全部的s2元素,结果的倒序即为所求的后缀表达式
代码一:(后缀表达式计算器,数组实现的栈)
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class PolandNotation {
public static void main(String[] args) {
System.out.println("请输入一个后缀表达式");
Scanner scanner = new Scanner(System.in);
String question = scanner.next();
List<String> listString = getListString(question);
System.out.println(findResult(listString));
}
//编写一个把字符串变为一个个单独的字符串格式
public static List<String> getListString(String value) {
ArrayList<String> arr = new ArrayList<>();
for (int i = 0; i < value.length(); i++) {
String single = value.substring(i, i + 1);
arr.add(single);
}
return arr;
}
//判断是否是操作符
public static boolean isOper(String val){
return val.equals("*") || val.equals("/") || val.equals("+") || val.equals("-");
}
//对传入的字符串列表进行计算
public static int findResult(List<String> list){
int num1,num2,tmp;
ArrayStack arrayStack = new ArrayStack(list.size());
for (String s : list) {
if (isOper(s)){
//是操作符,弹出数字计算
num2 = arrayStack.pop();
num1 = arrayStack.pop();
tmp = calculate(num1, num2, s);
arrayStack.push(tmp);
}else{
//是数字,入栈
arrayStack.push(Integer.parseInt(s));
}
}
return arrayStack.pop();
}
//计算逻辑
public static int calculate(int num1,int num2, String s){
switch(s) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num1 / num2;
}
//s只可能是以上四种,这里return 0 是为了不报错
return 0;
}
}
class ArrayStack{
int maxSize;
int[] array;
//栈顶指针默认指向-1,当有数据push后,top++,指向0号位
int top = -1;
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
array = new int[maxSize];
}
public void push(int num){
if (top == maxSize - 1){
System.out.println("栈满,无法添加");
return;
}
array[++top] = num;
}
public int pop(){
if (top == -1){
System.out.println("栈空,无法出栈");
return -9999999;
}
return array[top--];
}
public void popall(){
if (top == -1){
System.out.println("栈空,无法出栈");
return;
}
int i = 1;
while (top != -1){
System.out.println("第" + i++ + "个为" + array[top--]);
}
}
public void showall(){
if (top == -1){
System.out.println("栈空,无法出栈");
return;
}
for (int i = 0; i <= top; i++) {
System.out.println("第" + i + "个为" +array[i]);
}
}
}
代码二:(中缀表达式转换后缀表达式计算器)?
靠!写了一个多小时....这玩意儿果然不是我应该做的....
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class PolandNotation {
public static void main(String[] args) {
System.out.println("请输入一个表达式");
Scanner scanner = new Scanner(System.in);
String question = scanner.next();
//字符串转换为一个个的数字和操作符和括号
List<String> midList = toMidList(question);
//转换为后缀表达式
List<String> suffixList = toSuffixList(midList);
//计算后缀表达式
int result = figure(suffixList);
System.out.println(result);
//例:输入(3+4)*5-6 得到29!
}
//用该方法将输入的中缀字符串做一个划分,顺序划分成数字和操作符
public static List<String> toMidList(String question) {
ArrayList<String> arr = new ArrayList<>();
char c;//扫描变量
int i = 0;
while (i < question.length()){
if (question.charAt(i) < 48 || question.charAt(i) > 57){
//即不为数字
arr.add("" + question.charAt(i));
i++;
}else{
//如果是数字,需要判断是不是一个多位数
StringBuilder tmp = new StringBuilder();
//判断接着的几个数是不是数字
while (i < question.length() && question.charAt(i) >=48 && question.charAt(i) <=57){
tmp.append(question.charAt(i));
i++;
}
arr.add(tmp.toString());
}
}
return arr;
}
//转换后缀表达式
public static List<String> toSuffixList(List<String> mid) {
//定义两个栈
Stack<String> s1 = new Stack<String>(); // 符号栈
Stack<String> s2 = new Stack<String>(); // 中间栈
//开始遍历
for(String item: mid) {
if(item.matches("\\d+")) {
//是数字
s2.push(item);
} else if (item.equals("(")) {
//是左括号
s1.push(item);
} else if (item.equals(")")) {
//是右括号
while(!s1.peek().equals("(")) {//栈顶不为左括号
s2.push(s1.pop());
}
//轮到左括号
s1.pop();
} else {
//是操作符
while(s1.size() != 0 && getPri(s1.peek()) >= getPri(item) ) {
//item优先级小于栈顶
s2.push(s1.pop());
}
//当栈顶的优先级比当前item小时
s1.push(item);
}
}
//遍历结束
while(s1.size() != 0) {
s2.push(s1.pop());
}
//倒序返回 创建一个中间栈s3
Stack<String> s3 = new Stack<>();
while (s2.size() != 0){
s3.push(s2.pop());
}
ArrayList<String> arr= new ArrayList<>();
while (s3.size() != 0){
arr.add(s3.pop());
}
return arr;
}
//判断优先级
public static int getPri(String s){
switch (s){
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
}
return 0;
}
//判断是否是操作符
public static boolean isOper(String val){
return val.equals("*") || val.equals("/") || val.equals("+") || val.equals("-");
}
//对传入的字符串列表进行计算
public static int figure(List<String> list){
//后缀表达式的计算逻辑,很简单
Stack<String> s1 = new Stack<>();
int num1,num2,tmp;
for (String s : list) {
if (isOper(s)){
// TODO: 2021/12/4 栈顶元素为num2
num2 = Integer.parseInt(s1.pop());
num1 = Integer.parseInt(s1.pop());
s1.push(calculate(num1,num2,s)+"");
}else {
//是数字
s1.push(s);
}
}
return Integer.parseInt(s1.pop());
}
//计算逻辑
public static int calculate(int num1,int num2, String s){
switch(s) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num1 / num2;
}
//s只可能是以上四种,这里return 0 是为了不报错
return 0;
}
}
|