package 数据结构;
import java.util.Arrays;
import java.util.Queue;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @program: java_每天一题
* @description: 使用栈及队列实现中缀表达式转后缀表达式功能
* 思路:1.初始化一个栈存放运算符s1,初始化一个队列存放后缀表达式q1
* 2.从左自右扫描中缀表达式
* 3.遇到数字,放入队列q1中
* 4.遇到运算符,进行比较运算符优先级
* 4.1 如果s1为空或者遇到左括号“(”,直接入栈
* 4.2 如果运算符优先级比栈顶优先级高,直接入栈
* 4.3 如果运算符优先级比栈顶优先级低,或者相等,想将s1顶层运算符弹出放入q1,再次转到4.1与新的顶层运算符相比较
* 5.遇括号时,如果是左括号“(”,直接入栈.如果是右括号,则依次弹出s1栈顶运算符,放入q1中,直到遇到左括号为止,此时将一对括号抛弃
* 6 重复步骤2-5,直到表达式最右边
* 7 将q1顺序输出 得到后缀表达式(逆波兰表达式)
* @author: czg
* @create: 2020-05-16 11:15
*/
public class j_栈_中缀转后缀_逆波兰 {
public static void main(String[] args) {
System.out.println(Arrays.toString(infixToArrarSuffix("1+((2+3)*4)-5")));
}
/**
* 中缀表达式转后缀表达式(返回字符串格式)
* @param infix 中缀表达式
* @return
*/
public static String infixToStringSuffix(String infix){
Stack<String> s1=new Stack<>();//存放运算符
Queue<String> q1=new LinkedBlockingQueue<String>();//存放后缀表达式
int index=0;//循环中缀表达式下标
StringBuilder result=new StringBuilder();//结果
while (true){
//获得下标指定元素
String element=getOneElement(infix,index);
//如果是运算符
if(isOperator(element)){
//s1.peek() 查看栈顶
if(s1.empty()||"(".equals(element)||"(".equals(s1.peek())){
//如果s1为空或者遇到左括号“(”,直接入栈
s1.push(element);
}else if(")".equals(element)){
//如果是右括号,则依次弹出s1栈顶运算符,放入q1中,直到遇到左括号为止,此时将一对括号抛弃
while (!s1.peek().equals("(")){
q1.add(s1.pop());
}
//丢弃左括号
s1.pop();
}else if(operaPriority(element)>operaPriority(s1.peek())){
//如果运算符优先级比栈顶优先级高,直接入栈
s1.push(element);
}else if(operaPriority(element)<=operaPriority(s1.peek())){
//如果运算符优先级比栈顶优先级低,或者相等,想将s1顶层运算符弹出放入q1,再次转到4.1与新的顶层运算符相比较
while (operaPriority(element)<=operaPriority(s1.peek())){
q1.add(s1.pop());
if(s1.empty()){
s1.push(element);
break;
}
}
}else {
throw new RuntimeException("存在未知运算符,无法计算");
}
}else if(isInteger(element)){
//直接存入q1
q1.add(element);
}
index=index+element.length();
//当到达末尾时,结束循环
if(index>=infix.length()){
if(!s1.empty()){
q1.add(s1.pop());
}
break;
}
}
while (!q1.isEmpty()){
result.append(q1.poll());
}
return result.toString();
}
/**
* 中缀表达式转后缀表达式(返回字符串数组格式)
* @param infix 中缀表达式
* @return
*/
public static String[] infixToArrarSuffix(String infix){
Stack<String> s1=new Stack<>();//存放运算符
Queue<String> q1=new LinkedBlockingQueue<String>();//存放后缀表达式
int index=0;//循环中缀表达式下标
while (true){
//获得下标指定元素
String element=getOneElement(infix,index);
//如果是运算符
if(isOperator(element)){
//s1.peek() 查看栈顶
if(s1.empty()||"(".equals(element)||"(".equals(s1.peek())){
//如果s1为空或者遇到左括号“(”,直接入栈
s1.push(element);
}else if(")".equals(element)){
//如果是右括号,则依次弹出s1栈顶运算符,放入q1中,直到遇到左括号为止,此时将一对括号抛弃
while (!s1.peek().equals("(")){
q1.add(s1.pop());
}
//丢弃左括号
s1.pop();
}else if(operaPriority(element)>operaPriority(s1.peek())){
//如果运算符优先级比栈顶优先级高,直接入栈
s1.push(element);
}else if(operaPriority(element)<=operaPriority(s1.peek())){
//如果运算符优先级比栈顶优先级低,或者相等,想将s1顶层运算符弹出放入q1,再次转到4.1与新的顶层运算符相比较
while (operaPriority(element)<=operaPriority(s1.peek())){
q1.add(s1.pop());
if(s1.empty()){
s1.push(element);
break;
}
}
}else {
throw new RuntimeException("存在未知运算符,无法计算");
}
}else if(isInteger(element)){
//直接存入q1
q1.add(element);
}
index=index+element.length();
//当到达末尾时,结束循环
if(index>=infix.length()){
if(!s1.empty()){
q1.add(s1.pop());
}
break;
}
}
String[] result=new String[q1.size()];//结果
for (int i = 0; i < result.length; i++) {
result[i]=q1.poll();
}
return result;
}
//获得一个元素
public static String getOneElement(String experssion,int index){
int count=index;
String data="";
while (true){
String temp="";
if(experssion.length()==count+1)
{
temp=experssion.substring(index);
}else {
temp=experssion.substring(index,count+1);
}
if(isOperator(temp)){
data=temp;
break;
}
if(isInteger(temp)||temp.equals(".")){
data=temp;
if(experssion.length()==count+1){
break;
}
count++;
}else if(data.length()>0){
break;
}
}
return data;
}
//判断字符串是否为数字
public static boolean isInteger(String str) {
try {
new Double(str);
return true;
}catch (Exception e){
return false;
}
}
//判断是否是运算符
public static boolean isOperator(String str){
return "+-*/()".indexOf(str)>=0;
}
//设置字符优先级
public static int operaPriority(String opera){
int result=0;
switch (opera){
case "+":
case "-": break;
case "*":
case "/": result=1; break;
default:
throw new RuntimeException("运算符优先级无法解析");
}
return result;
}
}