**中缀表达式:**中缀表达式是一个通用的算术或逻辑公式表示方法
**后缀表达式:**也叫逆波兰式
关系:
中缀表达式:a+b
后缀表达式:a b +
我们对中缀表达式比较熟悉,对后缀表达式感觉难懂,但对于计算机来说,则后缀表达式比较好理解。
首先我们先看看后缀表达式如何运算:
1.a b +
假设有一个栈中存放数值;
从左到右我们如果遇见的是数值,则直接压入栈中,则栈中有a b 两个数值,当遇到运算符就从栈中取出两个数进行运算,将计算结果重新压入栈中,最后栈中的结构就是a+b;
2.ab+c*ab+e/-
同理:
1.-----> (a+b)
c *ab+e/-
a+b为一个数
2.-----> ( (a+b)*c)
ab+e/=
( (a+b)*c)是一个数
3.----->( (a+b)*c)
(a+b)
e/-
( (a+b)*c)是一个数(a+b)是一个数
4.-----> ( (a+b)*c)
(a+b)/e
-
( (a+b)*c)是一个数(a+b)/e是一个数
5.-----> (a+b)*c-(a+b)/e
最终结果
代码实现
//计算结果;s中存储的为后缀表达式
String[] s = postfix.split(" ");
//定义一个栈用来存储数值
Stack<Integer> numbers = new Stack<>();
for (String temp : s){
//如果是数值则直接入栈
if (temp.matches("\\d+")){
numbers.push(Integer.parseInt(temp));
}else {
//否则则将计算得到的值压入栈中
int num1 = numbers.pop();
int num2 =numbers.pop();
int compute = Compute(num1, num2, temp);
numbers.push(compute);
}
}
哪中缀表达式又是如何转换为后缀表达式的呢
我们用**(a+b)c-(a+b)/e* 举例说明
定义两个栈,一个用来存储表达式,一个用来存储运算符。
可以得到正确的后缀表达式
代码(没有考虑括号)
将中缀表达式先变为list然后变为后缀表达式
//得到一个list中缀表达式
public static ArrayList<String> getArrList(String exp){
char[] expChar = exp.toCharArray();
String s = "";
ArrayList<String> infix = new ArrayList<>();//保存中序表达式
for (int i = 0; i < expChar.length; i++) {
if (expChar[i] == '+' || expChar[i] == '-' || expChar[i] == '*' || expChar[i] == '/') {
infix.add(String.valueOf(expChar[i]));
} else {
s = s + (expChar[i] - '0');
//判断是否到达末尾
if (i + 1 < expChar.length) {
//如果待压入的数值的后一位不为运算符则拼接,否则直接压入
if (expChar[i + 1] == '+' || expChar[i + 1] == '-' || expChar[i + 1] == '*' || expChar[i + 1] == '/') {
infix.add(s);
s = "";
}
} else {
infix.add(s);
}
}
}
return infix;
}
public static String infixTOPostfix(ArrayList<String> list){
//定义两个栈 一个存表达式,一个用来存运算符
Stack<String> oper = new Stack<>();
Stack<String> expr = new Stack<>();
//判断是运算符还是数值
for (String a : list) {
if (a.equals("+") || a.equals("-") || a.equals("*") || a.equals("/")) {
//如果优先级高则直接入运算符栈
while (true) {
if (oper.isEmpty() || priority(a) > priority(oper.peek())) {
oper.push(a);
break;
//否则将顶部的运算符取出压入表达式的栈
} else {
expr.push(oper.pop());
}
}
//数值直接压入
} else {
expr.push(a);
}
}
//最后如果运算符栈中还有数值,则压入表达式栈
while (!oper.isEmpty()){
expr.push(oper.pop());
}
//用一个字符串 来结构表达式栈中的表达式,进行拼接
StringBuilder s= new StringBuilder();
while (!expr.isEmpty()){
if (expr.size()!=1) {
s.append(expr.pop()).append(" ");
}else {
s.append(expr.pop());
}
}
//将刚拼接的表达式进行反转
String[] str = s.toString().split(" ");
StringBuilder temp = new StringBuilder();
for (int i = str.length-1;i>=0;i--){
if (i>0){
temp.append(str[i]).append(" ");
}else {
temp.append(str[i]);
}
}
return temp.toString();
}
变为后缀表达式后,就可以直接计算。
下面为完整代码
package stack.postfixexpression;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Stack;
public class Calculate {
public static void main(String[] args) {
//接受一个表达式
Scanner sc = new Scanner(System.in);
System.out.println("请输入表达式");
String expression;
expression = sc.nextLine();
//将表达式用链表连接,将数值和运算符分开
ArrayList<String> list =getArrList(expression);
System.out.println(list);
//将中缀表达式转换为后缀表达式
System.out.println("----------");
String postfix = infixTOPostfix(list);
System.out.println(postfix);
System.out.println("-----------");
//计算结果;
String[] s = postfix.split(" ");
//定义一个栈用来存储数值
Stack<Integer> numbers = new Stack<>();
for (String temp : s){
//如果是数值则直接入栈
if (temp.matches("\\d+")){
numbers.push(Integer.parseInt(temp));
}else {
//否则则将计算得到的值压入栈中
int num1 = numbers.pop();
int num2 =numbers.pop();
int compute = Compute(num1, num2, temp);
numbers.push(compute);
}
}
System.out.println(numbers.pop());
}
//得到中缀表达式
//得到一个list中缀表达式
public static ArrayList<String> getArrList(String exp){
char[] expChar = exp.toCharArray();
String s = "";
ArrayList<String> infix = new ArrayList<>();//保存中序表达式
for (int i = 0; i < expChar.length; i++) {
if (expChar[i] == '+' || expChar[i] == '-' || expChar[i] == '*' || expChar[i] == '/') {
infix.add(String.valueOf(expChar[i]));
} else {
s = s + (expChar[i] - '0');
//判断是否到达末尾
if (i + 1 < expChar.length) {
//如果待压入的数值的后一位不为运算符则拼接,否则直接压入
if (expChar[i + 1] == '+' || expChar[i + 1] == '-' || expChar[i + 1] == '*' || expChar[i + 1] == '/') {
infix.add(s);
s = "";
}
} else {
infix.add(s);
}
}
}
return infix;
}
public static String infixTOPostfix(ArrayList<String> list){
//定义两个栈 一个存表达式,一个用来存运算符
Stack<String> oper = new Stack<>();
Stack<String> expr = new Stack<>();
//判断是运算符还是数值
for (String a : list) {
if (a.equals("+") || a.equals("-") || a.equals("*") || a.equals("/")) {
//如果优先级高则直接入运算符栈
while (true) {
if (oper.isEmpty() || priority(a) > priority(oper.peek())) {
oper.push(a);
break;
//否则将顶部的运算符取出压入表达式的栈
} else {
expr.push(oper.pop());
}
}
//数值直接压入
} else {
expr.push(a);
}
}
//最后如果运算符栈中还有数值,则压入表达式栈
while (!oper.isEmpty()){
expr.push(oper.pop());
}
//用一个字符串 来结构表达式栈中的表达式,进行拼接
StringBuilder s= new StringBuilder();
while (!expr.isEmpty()){
if (expr.size()!=1) {
s.append(expr.pop()).append(" ");
}else {
s.append(expr.pop());
}
}
//将刚拼接的表达式进行反转
String[] str = s.toString().split(" ");
StringBuilder temp = new StringBuilder();
for (int i = str.length-1;i>=0;i--){
if (i>0){
temp.append(str[i]).append(" ");
}else {
temp.append(str[i]);
}
}
return temp.toString();
}
//自定义优先级
public static int priority(String num) {
if (num.equals("+") || num.equals("-")) {
return 0;
}
if (num.equals("*") || num.equals("/")) {
return 1;
}
throw new RuntimeException("表达式有误");
}
public static int Compute(int num1, int num2, String ope) {
if (ope.equals("+")) {
return num1 + num2;
}
if (ope.equals("-")) {
return num2 - num1 ;
}
if (ope.equals("*")) {
return num1*num2;
}
if (ope.equals("/")) {
return num2 / num1 ;
}
throw new RuntimeException("计算有误");
}
}
请大家多多指教!