中缀表达式转后缀表达式(考虑了多位数的情况)
需要用到的ascll码
*42
+43
-45
/47
(40
)41
思路
1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2.从左至右扫描中缀表达式;
3.遇到操作数时,将其压s2;
4.遇到运算符时,分类讨论
4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
5.遇到括号时:
5.1如果是左括号“(",则直接压入s1
5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6.重复步骤2至5,直到表达式的最右边
7.将s1中剩余的运算符依次弹出并压入s2
8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
算法
/**
* 中缀表达式转后缀表达式
* @param expression
* @return
*/
public static String transfer(String expression) {
//1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
Stack<String> s1 = new Stack<>();//运算符栈
Stack<String> s2 = new Stack<>();//储存中间结果的栈
int index = 0;
String keepNum = "";//用于拼接多位数
//2.从左至右扫描中缀表达式;
while (index < expression.length()) {
char c = expression.charAt(index);
//3.遇到操作数时,将其压s2;
if (c >= 48 && c <= 57) {
//且数字为表达式最后一位,则直接入栈s2
if(index+1 == expression.length()){
s2.push(String.valueOf(c));
}
keepNum += c;
index++;
}
//4.如果字符c为运算符 分类讨论
else if (c == 42 || c == 43 || c == 45 || c == 47) {
s2.push(keepNum);
keepNum = "";
//4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
if (s1.isEmpty() || "(".equals(s1.peek())) {
s1.push(String.valueOf(c));
index++;
}
//4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
else if (priority(c) > priority(s1.peek().charAt(0))) {
s1.push(String.valueOf(c));
index++;
}
//4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
else {
s2.push(s1.pop());
}
}
//5.如果遇到括号
//5.1如果是左括号“(",则直接压入s1,继续遍历
else if ('(' == c) {
s2.push(keepNum);
keepNum = "";
s1.push(String.valueOf(c));
index++;
}
//5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
else if (')' == c) {
s2.push(keepNum);
keepNum = "";
while (true) {
String pop = s1.pop();
if ("(".equals(pop)) {
break;
}
s2.push(pop);
}
index++;
}
//6.重复步骤2至5,直到表达式的最右边
}
//遍历结束后将s1中剩余的运算符依次弹出并压入s2,再逆序输出s2就得到了后缀表达式
//7.将s1中剩余的运算符依次弹出并压入s2
while(!s1.isEmpty()){
String pop = s1.pop();
s2.push(pop);
}
String suffixExpression = "";
while (!s2.isEmpty()) {
String pop = s2.pop();
suffixExpression += pop + " ";
}
//根据空格分割
String[] s = suffixExpression.split(" ");
ArrayList<String> arrayList =new ArrayList<>();
//去除多余空格
for (String s3 : s) {
if(!"".equals(s3)){
arrayList.add(s3);
}
}
//8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
Collections.reverse(arrayList);
String s4 = "";
for (String s3 : arrayList) {
s4+=s3+" ";//此处又添加空格是为了方便给calculate函数计算,因为calculate函数需要有空格间隙的表达式
}
return s4;
}
计算简单后缀表达式
思路
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素和栈顶元素),并将结果入栈;
重复上述过程直到表达式最右端,最后栈中的值即为表达式的结果
算法
/**
* 计算后缀表达式
* @param suffixExpression
*/
public static void calculate(String suffixExpression) {
String[] s = suffixExpression.split(" ");
Stack<Integer> stack = new Stack<>();
for (String s1 : s) {
int i;
//如果是运算符号,使用Integer.parseInt()会报NumberFormatException 以此来判断是不是运算符
try {
i = Integer.parseInt(s1);
} catch (NumberFormatException e) {
i = s1.charAt(0);
}
//如果是运算符
if (i == 43 || i == 45 || i == 47 || i == 42) {
Integer pop1 = stack.pop();
Integer pop2 = stack.pop();
int result = 0;
switch (i) {
case 42:
result = pop1 * pop2;
stack.push(result);
break;
case 43:
result = pop1 + pop2;
stack.push(result);
break;
case 45:
result = pop2 - pop1;
stack.push(result);//除法(减法)需要用次顶元素除以(减)栈顶元素
break;
case 47:
result = pop2 / pop1;
stack.push(result);//除法(减法)需要用次顶元素除以(减)栈顶元素
break;
default:
break;
}
}
//如果非运算符,就将数字入栈
else {
stack.push(i);
}
}
Integer peek = stack.peek();
System.out.println(peek);
}
//为运算符分配优先级
public static int priority(char c) {
if (c == '*' || c == '/') {
return 1;
}
if (c == '-' || c == '+') {
return 0;
}
if (c == '(' || c == ')') {
return 2;
}
return -1;//传入的符号不是运算符
}
根据算法思路结合代码,遇到疑问可以进行debug或者举简单例子进行画图理解
完整代码
package stack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;
/**
* @author Watching
* * @date 2022/11/1
* * Describe:
* 一,中缀表达式转后缀表达式 (考虑了多位数的情况
* 思路:
* 1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
* 2.从左至右扫描中缀表达式;
* 3.遇到操作数时,将其压s2;
* 4.遇到运算符时,分类讨论;
* 4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
* 4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
* 4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
* 5.遇到括号时:
* 5.1如果是左括号“(",则直接压入s1
* 5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
* 6.重复步骤2至5,直到表达式的最右边
* 7.将s1中剩余的运算符依次弹出并压入s2
* 8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
* <p>
* <p>
* 二,逆波兰表达式计算
* 思路:
* 从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次项元素和栈项元素),并将结果入栈;
* 重复上述过程直到表达式最右端,最后栈中的值即为表达式的结果
* <p>
* <p>
* 三,ascll码
* * 42
* + 43
* - 45
* / 47
* ( 40
* ) 41
*/
public class PolandNotation {
public static void main(String[] args) {
// String suffixExpression = "30 4 + 5 * 6 -";//(30+4)*5-6
// calculate(suffixExpression);
String expression = "(30+4)*5-6";
String suffixExpression = transfer(expression);
calculate(suffixExpression);
}
/**
* 中缀表达式转后缀表达式
* @param expression
* @return
*/
public static String transfer(String expression) {
//1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
Stack<String> s1 = new Stack<>();//运算符栈
Stack<String> s2 = new Stack<>();//储存中间结果的栈
int index = 0;
String keepNum = "";//用于拼接多位数
//2.从左至右扫描中缀表达式;
while (index < expression.length()) {
char c = expression.charAt(index);
//3.遇到操作数时,将其压s2;
if (c >= 48 && c <= 57) {
//且数字为表达式最后一位,则直接入栈s2
if(index+1 == expression.length()){
s2.push(String.valueOf(c));
}
keepNum += c;
index++;
}
//4.如果字符c为运算符 分类讨论
else if (c == 42 || c == 43 || c == 45 || c == 47) {
s2.push(keepNum);
keepNum = "";
//4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
if (s1.isEmpty() || "(".equals(s1.peek())) {
s1.push(String.valueOf(c));
index++;
}
//4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
else if (priority(c) > priority(s1.peek().charAt(0))) {
s1.push(String.valueOf(c));
index++;
}
//4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
else {
s2.push(s1.pop());
}
}
//5.如果遇到括号
//5.1如果是左括号“(",则直接压入s1,继续遍历
else if ('(' == c) {
s2.push(keepNum);
keepNum = "";
s1.push(String.valueOf(c));
index++;
}
//5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
else if (')' == c) {
s2.push(keepNum);
keepNum = "";
while (true) {
String pop = s1.pop();
if ("(".equals(pop)) {
break;
}
s2.push(pop);
}
index++;
}
//6.重复步骤2至5,直到表达式的最右边
}
//遍历结束后将s1中剩余的运算符依次弹出并压入s2,再逆序输出s2就得到了后缀表达式
//7.将s1中剩余的运算符依次弹出并压入s2
while(!s1.isEmpty()){
String pop = s1.pop();
s2.push(pop);
}
String suffixExpression = "";
while (!s2.isEmpty()) {
String pop = s2.pop();
suffixExpression += pop + " ";
}
//根据空格分割
String[] s = suffixExpression.split(" ");
ArrayList<String> arrayList =new ArrayList<>();
//去除多余空格
for (String s3 : s) {
if(!"".equals(s3)){
arrayList.add(s3);
}
}
//8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
Collections.reverse(arrayList);
String s4 = "";
for (String s3 : arrayList) {
s4+=s3+" ";//此处又添加空格是为了方便给calculate函数计算,因为calculate函数需要有空格间隙的表达式
}
return s4;
}
/**
* 计算后缀表达式
* @param suffixExpression
*/
public static void calculate(String suffixExpression) {
String[] s = suffixExpression.split(" ");
Stack<Integer> stack = new Stack<>();
for (String s1 : s) {
int i;
//如果是运算符号,使用Integer.parseInt()会报NumberFormatException 以此来判断是不是运算符
try {
i = Integer.parseInt(s1);
} catch (NumberFormatException e) {
i = s1.charAt(0);
}
//如果是运算符
if (i == 43 || i == 45 || i == 47 || i == 42) {
Integer pop1 = stack.pop();
Integer pop2 = stack.pop();
int result = 0;
switch (i) {
case 42:
result = pop1 * pop2;
stack.push(result);
break;
case 43:
result = pop1 + pop2;
stack.push(result);
break;
case 45:
result = pop2 - pop1;
stack.push(result);
break;
case 47:
result = pop2 / pop1;
stack.push(result);
break;
default:
break;
}
}
//如果非运算符,就将数字入栈
else {
stack.push(i);
}
}
Integer peek = stack.peek();
System.out.println(peek);
}
//为运算符分配优先级
public static int priority(char c) {
if (c == '*' || c == '/') {
return 1;
}
if (c == '-' || c == '+') {
return 0;
}
if (c == '(' || c == ')') {
return 2;
}
return -1;//传入的符号不是运算符
}
}