中缀转后缀
1)对表达式字符串中的数分别取出
2)对取出的字符做判断,符号存入,数字考虑拼接
3)再将取出的字符统一存储起来
4)初始化两个栈:运算符栈和储存中间结果的栈s2
5)从左至右扫描中缀表达式;
6)遇到操作数时,将其压入s2
7)遇到运算符时,比较其与s1栈顶运算符的优先级:
1.如果s1为空或栈顶运算符为左括号“(”,则直接将此运算符入栈
2.否则,若优先级比栈顶运算符高,也将运算符压入到s1
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(7).1)与s1中新的栈顶运算符相比较﹔
8)遇到括号时:
1.如果是左括号“(”,则直接压入s1
2.如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
9)重复5-8,直至表达式中全部字符被操作
10)将s1中剩余的运算符依次弹出并压入s2
11)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
public static List<String> toInfixExpression(String s){
//创建一个集合来存放字符串分隔后的数据
List<String> ls=new ArrayList<String>();
//对字符串中字符取出时的索引
int i=0;
//用于拼接多位数
String str;
//定义字符承接从字符串中读取的字符
char c;
do {
//数字0-9对应的ASCII码为48-57
if ((c=s.charAt(i))>48||(c=s.charAt(i))<57)
{
//非数字,直接加入集合中
ls.add(""+c);
i++;//索引后移
}else {
//数字,考虑是否是多位
str="";
//如果多位,就一直拼接
while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
str+=c;
i++;
}
//数放入集合中
ls.add(str);
}
}while (i<s.length());
//返回集合
return ls;
}
//由中缀表达式的集合得到后缀表达式的集合
public static List<String> toPostfixExpression(List<String> list){
Stack<String> s1=new Stack<String>();
List<String> l2=new ArrayList<String>();
int i;
for(String s:list){
if(s.charAt(0)<48||s.charAt(0)>57){
if (s1.empty()){
s1.push(s);
}else if(isOper(s.charAt(0))){
while(true){
if (s1.isEmpty()){
s1.push(s);
break;
}else if (s1.peek().equals("(")){
s1.push(s);
break;
}else if (priority(s.charAt(0))>priority(s1.peek().charAt(0))){
s1.push(s);
break;
}else{
l2.add(s1.pop());
continue;
}
}
}else if(s.equals("(")){
s1.push(s);
}else if (s.equals(")")){
while (true){
if (s1.peek().equals("(")){
s1.pop();
break;
}else {
l2.add(s1.pop());
}
}
}
}else {
l2.add(s);
}
}
while (true){
if (s1.isEmpty()){
break;
}
l2.add(s1.pop());
}
return l2;
}
由上述转化过程,我们可以进行以下实践
利用逆波兰表达式实现综合计算机
package Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
//逆波兰表达式计算(3+4)*5-6
public class PolandNotation {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
List<String> l1=new ArrayList<String>();
List<String> l2=new ArrayList<String>();
//输入中缀表达式
String infixExpression=scanner.next();
//中缀表达式转中缀字符集合
l1=toInfixExpression(infixExpression);
l2=toPostfixExpression(l1);
String postfixExpression=toPost(l2);
//因为我们需要计算数值但逆波兰表达式被我们赋给了字符串类型,所以我们需要一个方法帮我们处理逆波兰的字符串
List<String> rpnList=getListString(postfixExpression);
//为了使主程序看起来更加简洁,这里定义一个计算方法将得到的集合放入计算得到结果
int res=calculate(rpnList);
System.out.println(infixExpression+"计算结果为"+res);
}
//后缀表达式各字符的集合和转后缀表达式
public static String toPost(List<String> l2){
String postExpression="";
for (int i=0;i<l2.size();i++){
if (i==l2.size()-1){
postExpression+= l2.get(i);
break;
}
postExpression+=l2.get(i);
postExpression+=" ";
}
return postExpression;
}
//由中缀表达式的集合得到后缀表达式的集合
public static List<String> toPostfixExpression(List<String> list){
Stack<String> s1=new Stack<String>();
List<String> l2=new ArrayList<String>();
int i;
for(String s:list){
if(s.charAt(0)<48||s.charAt(0)>57){
if (s1.empty()){
s1.push(s);
}else if(isOper(s.charAt(0))){
while(true){
if (s1.isEmpty()){
s1.push(s);
break;
}else if (s1.peek().equals("(")){
s1.push(s);
break;
}else if (priority(s.charAt(0))>priority(s1.peek().charAt(0))){
s1.push(s);
break;
}else{
l2.add(s1.pop());
continue;
}
}
}else if(s.equals("(")){
s1.push(s);
}else if (s.equals(")")){
while (true){
if (s1.peek().equals("(")){
s1.pop();
break;
}else {
l2.add(s1.pop());
}
}
}
}else {
l2.add(s);
}
}
while (true){
if (s1.isEmpty()){
break;
}
l2.add(s1.pop());
}
return l2;
}
//定义一个方法处理中缀表达式,将其转化为一个集合
public static List<String> toInfixExpression(String s){
//创建一个集合来存放字符串分隔后的数据
List<String> ls=new ArrayList<String>();
//对字符串中字符取出时的索引
int i=0;
//用于拼接多位数
String str;
//定义字符承接从字符串中读取的字符
char c;
do {
//数字0-9对应的ASCII码为48-57
if ((c=s.charAt(i))>48||(c=s.charAt(i))<57)
{
//非数字,直接加入集合中
ls.add(""+c);
i++;//索引后移
}else {
//数字,考虑是否是多位
str="";
//如果多位,就一直拼接
while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
str+=c;
i++;
}
//数放入集合中
ls.add(str);
}
}while (i<s.length());
//返回集合
return ls;
}
//定义一个方法处理字符串
public static List<String> getListString(String str){
//split函数将字符串分隔成子字符串
String[] split=str.split(" ");
//将子字符串存入集合中便于后续操作
List<String> list =new ArrayList<String>();
for (String ele:split){
list.add(ele);
}
//将集合返回
return list;
}
//计算方法
public static int calculate(List<String> list){
//定义一个存放字符串的栈,用来存放数字字符
Stack<String> stack=new Stack<String>();
//通过遍历集合元素来实现计算
//如果得到运算符号,则弹出栈中栈顶和次顶字符进行转型运算
//如果得到数字字符(正则表达式判断),则存入栈中
for (String da:list){
if (da.matches("\\d+")){
stack.push(da);
}else {
int num1=Integer.parseInt(stack.pop());
int num2=Integer.parseInt(stack.pop());
int res=0;
if(da.equals("+")){
res=num1+num2;
}else if (da.equals("-")){
res=num2-num1;
}else if (da.equals("*")){
res=num1*num2;
}else if (da.equals("/")){
res=num2/num1;
}else {
throw new RuntimeException("运算符有误");
}
stack.push(res+"");
}
}
return Integer.parseInt(stack.pop());
}
public static int priority(char oper){
if (oper=='*'||oper=='/')
return 1;
else if (oper=='+'||oper=='-')
return 0;
//乘除计算优先级大于加减
else return -1;//简单计算只包含+,-,*,/
}
//判断是否是运算符
public static boolean isOper(char val){
return val=='+'||val=='-'||val=='*'||val=='/';
}
}