转载请标明出处,谢谢!
中缀表达式转后缀表达式思路:
从左至右依次遍历中缀表达式各个字符(需要准备一个字符栈存储操作符和括号)
1、字符为 运算数 :
直接送入后缀表达式(需要先分析出完整的运算数,即:-4、150这种数字要当作一个整体)。
2、字符为 左括号 :
直接入栈(左括号入栈后优先级降至最低)。
3、字符为 右括号 :
直接出栈,并将出栈字符依次送入后缀表达式,直到栈顶字符为左括号(左括号也要出栈,但不送入后缀表达式)。
总结:只要满足 栈顶为左括号 即可进行最后一次出栈。
4、字符为 操作符 :
若栈空,直接入栈。
若栈非空,判断栈顶操作符,若栈顶操作符优先级低于该操作符,该操作符入栈;否则一直出栈,并将出栈字符依次送入后缀表达式,直到栈空或栈顶操作符优先级低于该操作符,该操作符再入栈。
5、重复以上步骤直至遍历完成中缀表达式,接着判断字符栈是否为空,非空则直接出栈,并将出栈字符依次送入后缀表达式。
注:中缀表达式遍历完成,栈中可能还有字符未输出,故需要判断栈空。
中缀表达式转后缀表达式Java实现:
(1) 首先需要将中缀表达式拆分成字符串数组,使用 String2List
public static List<String> String2List(String s){
List<String> list = new ArrayList<>();
String temp = "";
for(int i=0; i<s.length();i++){
char c = s.charAt(i);
if(Character.isDigit(c)){
if(i!=s.length()-1 && Character.isDigit(s.charAt(i+1))){
temp += c;
}else{
temp += c;
list.add(temp);
temp = "";
}
}else if(c == '-'){
//对负数特殊处理(如“-4”要当作一个操作数来处理)
if(i == 0 || s.charAt(i-1) == '('){
temp += c;
}else{
list.add(c + "");
}
}else{
list.add(c + "");
}
}
return list;
}
(2) 将得到的字符串数组传入 mid2back , 进行表达式的转换,其中需要对字符串进行判断,按照是否为操作数进行划分,此功能由 isNum 提供
public static List<String> mid2back(List<String> s){
List<String> ss = new ArrayList<>();
Stack<String> stack = new Stack<String>();
for(int i=0; i<s.size(); i++){
String c = s.get(i);
//System.out.println(c);
//数字直接输出,字符判断入栈(请注意:左括号的优先级,入栈后视为最低)
if(isNum(c)){
ss.add(c);
}else{
if(c.equals("(") || stack.isEmpty()){
stack.push(c);
}
else if(c.equals(")")){
//出栈直到碰到左括号
while(!stack.peek().equals("(")){
ss.add(stack.pop());
}
//左括号弹出去
stack.pop();
}
else if(c.equals("*") || c.equals("/")){
//栈顶运算符优先级低于当前操作符,入栈
if(stack.peek().equals("+") || stack.peek().equals("-") || stack.peek().equals("(") ){
stack.push(c);
}else{
//出栈,直到栈顶优先级低于当前操作符,或者栈空,然后入栈
while(!stack.isEmpty() && (stack.peek().equals("*") || stack.peek().equals("/"))){
ss.add(stack.pop());
}
stack.push(c);
}
}
else if(c.equals("+") || c.equals("-")){
if(stack.peek() == "("){
stack.push(c);
}else{
while(!stack.isEmpty() && !stack.peek().equals("(") ){
ss.add(stack.pop());
}
stack.push(c);
}
}
}
}
//如果栈内还有运算符,直接弹出,直到栈空
while(!stack.isEmpty()){
ss.add(stack.pop());
}
//System.out.println(ss);
return ss;
}
public static boolean isNum(String s){
for(int i = 0; i <= 9; i++){
if(s.contains(i+"")){
return true;
}
}
return false;
}
后缀表达式计算思路:
从左到右扫描后缀表达式,遇到数字就入栈,遇到操作符就从栈弹出两个数字,然后计算得到的值继续入栈,继续扫描表达式,直到扫描完毕得到结果。
给出图例如下:
后缀表达式计算Java实现:
public static String backCal(List<String> ss){
//这里必须为String类型,不然后边字符和数字的转换会出现问题
Stack<String> stack = new Stack<>();
for(int i=0; i<ss.size(); i++){
String c = ss.get(i);
//数字直接入栈
if(isNum(c)){
stack.push(c);
}
//运算符,取出来并计算,再放进去
else{
Long b = Long.parseLong(stack.pop());
Long a = Long.parseLong(stack.pop());
switch(c){
case "+":
stack.push(Long.toString(a + b));
break;
case "-":
stack.push(Long.toString(a - b));
break;
case "*":
stack.push(Long.toString(a * b));
break;
case "/":
stack.push(Long.toString(a / b));
break;
}
}
}
return stack.pop();
}
整体代码:
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
//先把所有括号统一
s = s.replace("{","(");
s = s.replace("[","(");
s = s.replace("}",")");
s = s.replace("]",")");
//初始字符串预处理(提取数字整体作为一个字符串,创建字符串数组,其中包含对负数的处理)
List<String> list = String2List(s);
//中缀表达式转后缀表达式
List<String> ss = mid2back(list);
//后缀表达式计算
System.out.print(backCal(ss));
}
public static List<String> mid2back(List<String> s){
List<String> ss = new ArrayList<>();
Stack<String> stack = new Stack<String>();
for(int i=0; i<s.size(); i++){
String c = s.get(i);
//System.out.println(c);
//数字直接输出,字符判断入栈(请注意:左括号的优先级,入栈后视为最低)
if(isNum(c)){
ss.add(c);
}else{
if(c.equals("(") || stack.isEmpty()){
stack.push(c);
}
else if(c.equals(")")){
//出栈直到碰到左括号
while(!stack.peek().equals("(")){
ss.add(stack.pop());
}
//左括号弹出去
stack.pop();
}
else if(c.equals("*") || c.equals("/")){
//栈顶运算符优先级低于当前操作符,入栈
if(stack.peek().equals("+") || stack.peek().equals("-") || stack.peek().equals("(") ){
stack.push(c);
}else{
//出栈,直到栈顶优先级低于当前操作符,或者栈空,然后入栈
while(!stack.isEmpty() && (stack.peek().equals("*") || stack.peek().equals("/"))){
ss.add(stack.pop());
}
stack.push(c);
}
}
else if(c.equals("+") || c.equals("-")){
if(stack.peek() == "("){
stack.push(c);
}else{
while(!stack.isEmpty() && !stack.peek().equals("(") ){
ss.add(stack.pop());
}
stack.push(c);
}
}
}
}
//如果栈内还有运算符,直接弹出,直到栈空
while(!stack.isEmpty()){
ss.add(stack.pop());
}
//System.out.println(ss);
return ss;
}
public static String backCal(List<String> ss){
//这里必须为String类型,不然后边字符和数字的转换会出现问题
Stack<String> stack = new Stack<>();
for(int i=0; i<ss.size(); i++){
String c = ss.get(i);
//数字直接入栈
if(isNum(c)){
stack.push(c);
}
//运算符,取出来并计算,再放进去
else{
Long b = Long.parseLong(stack.pop());
Long a = Long.parseLong(stack.pop());
switch(c){
case "+":
stack.push(Long.toString(a + b));
break;
case "-":
stack.push(Long.toString(a - b));
break;
case "*":
stack.push(Long.toString(a * b));
break;
case "/":
stack.push(Long.toString(a / b));
break;
}
}
}
return stack.pop();
}
public static boolean isNum(String s){
for(int i = 0; i <= 9; i++){
if(s.contains(i+"")){
return true;
}
}
return false;
}
public static List<String> String2List(String s){
List<String> list = new ArrayList<>();
String temp = "";
for(int i=0; i<s.length();i++){
char c = s.charAt(i);
if(Character.isDigit(c)){
if(i!=s.length()-1 && Character.isDigit(s.charAt(i+1))){
temp += c;
}else{
temp += c;
list.add(temp);
temp = "";
}
}else if(c == '-'){
//对负数特殊处理(如“-4”要当作一个操作数来处理)
if(i == 0 || s.charAt(i-1) == '('){
temp += c;
}else{
list.add(c + "");
}
}else{
list.add(c + "");
}
}
return list;
}
}
输入描述:
输入一个算术表达式,保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。
输出描述:
得到计算结果