前置知识:链表、队列、栈、波兰表达式、中缀表达式和后缀表达式
运行:
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
System.out.println(str + "=" + rpn.execute(str));
}
}
结果:
代码细节↓
第一步接收输入,拆分字符串,将运算符和数字分离,存储到一个链表中
public class RPN2
{
//表达式输入,字符串分解;分离操作符和操作数
public ArrayList<Object> strExecute(String str) throws Exception
{
//将表达式的每个字符用数组链表存储
ArrayList<Object> result = new ArrayList<>();
str = str.trim();
for(int i = 0; i < str.length(); i ++)
{
String op = "";
//若这个字符为数字,则继续遍历下一个元素,直到元素为非数字
while(str.charAt(i) >= 48 && str.charAt(i) <= 57 || str.charAt(i) == '.')
{
//若为连续数字,则拼接起来
op += str.charAt(i);
i ++;
if(i >= str.length())
break;
}
//若字符串不等于空,则一定为数字字符串
if(!op.equals("") && op.length() > 0 && !op.equals(" "))
result.add(Double.valueOf(op)); //将数字字符转换为Double类型(方便后续计算)添加至链表
if(i >= str.length())
break;
if(str.charAt(i) == ' ') //若为空格,则跳到下一次循环
continue;
//不为数字(即操作符)
if(str.charAt(i) < 48 || str.charAt(i) > 57)
{
char op2 = str.charAt(i);
if(op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == '(' || op2 == ')')
result.add(str.charAt(i) + ""); //操作符转成字符串添加到链表
else throw new Exception("不合法的运算符:" + "\"" + op2 + "\"");
}
}
return result; //返回表达式链表
}
// 把表达式转成字符串,方便调试显示
public String toString(ArrayList<Object> expr)
{
String result = "";
for(Object item: expr)
{
result += item.toString() + " ";
}
return result;
}
单元测试:
将每个字符单元拆分出来,也就是中缀表达式
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
ArrayList<Object> e = rpn.strExecute(str);
System.out.println("拆分后:" + e);
System.out.println("中缀表达式为:" + rpn.toString(e));
}
}
输出
第二步将中缀表达式转换成后缀表达式,后缀表达式我后面会出一篇文章详解,这里就先请移步百度
//后缀表达式转换
public ArrayList<Object> convert(ArrayList<Object> src)
{
ArrayList<Object> dst = new ArrayList<>();
Stack stack = new Stack();
for(Object item : src)
{
if(item instanceof Integer || item instanceof Double) //操作数
{
dst.add(item);
}
else if(item instanceof String) //操作符
{
String op = ((String) item).trim();
int p1 = priority(op); //操作符优先级
if(op.equals("("))
{
stack.push(op);
}
else if(op.equals(")"))
{
//直到匹配到左括号
while(stack.size() > 0)
{
String op2 = (String) stack.pop();
if(op2.equals("(")) break;
dst.add(op2);
}
}
else
{
//从stack弹出操作符,一直到遇到左括号,或者遇到比自己优先级低的符号
while(stack.size() > 0)
{
String op2 = (String) stack.peek(); //仅查看,不弹出
int p2 = priority(op2);
if(op2.equals("(")) //左括号应留在栈内
break;
if(p2 < p1) //遇到比自己优先级低的符号
break;
dst.add(op2);
stack.pop();
}
stack.push(op);
}
}
}
while (stack.size() > 0)
{
dst.add(stack.pop());
}
return dst;
}
//运算符优先级
public int priority(String op)
{
if("+ -".indexOf(op) >= 0) return 1;
if("* /".indexOf(op) >= 0) return 2;
return 0;
}
单元测试:
将中缀表达式转换成了后缀表达式
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
ArrayList<Object> e = rpn.strExecute(str);
System.out.println("中缀表达式为:" + rpn.toString(e));
ArrayList<Object> e2 = rpn.convert(e);
System.out.println("后缀表达式为:" + rpn.toString(e2));
}
}
输出
将链表转换为队列,后面计算需要
//链表转队列
public Queue<Object> list2Queue(List<Object> list)
{
Queue<Object> queue = new ArrayDeque<>();
Iterator<Object> iterator = list.iterator();
while(iterator.hasNext())
{
queue.add(iterator.next());
}
return queue;
}
最后一步,后缀表达式的计算,返回结果
//后缀表达式计算
public Object calculation(Queue<Object> src)
{
Stack stack = new Stack(); //用于存放操作数
while(src.size() > 0)
{
//从队列中弹出一个元素
Object item = src.poll();
//若元素为操作数,则直接入栈
if(item instanceof Double || item instanceof Integer)
{
stack.push(item);
}
//若元素为操作符,则弹出栈内最上层的两个操作数进行运算,将结果压栈
else if(item instanceof String)
{
//操作符(+ - * /)
String op = (String) item;
Double right = (Double) stack.pop(); //弹出一个数
Double left = (Double) stack.pop();
Double sum = 0.0d; //结果
if(op.equals("+"))
sum = left + right;
else if(op.equals("-"))
sum = left - right;
else if(op.equals("*"))
sum = left * right;
else if(op.equals("/"))
sum = left / right;
stack.push(sum); //将计算结果入栈
}
}
return stack.pop(); //最终栈内存储的是一个计算结果,将之弹出
}
测试代码:
import java.util.ArrayList;
import java.util.Queue;
public class Test
{
public static void main(String[] args) throws Exception {
RPN2 rpn = new RPN2();
String str = "(5*(4+2)+10)/(4+2*2)";
ArrayList<Object> e = rpn.strExecute(str);
System.out.println("中缀表达式为:" + rpn.toString(e));
ArrayList<Object> e2 = rpn.convert(e);
System.out.println("后缀表达式为:" + rpn.toString(e2));
//将后缀表达式的链表转换为队列
Queue<Object> queue = rpn.list2Queue(e2);
Object result = rpn.calculation(queue);
System.out.println("结果:" + result);
}
}
输出
一步到位
//执行计算
public Object execute(String expression) throws Exception
{
//拆分表达式字符串,将数字和运算符分离
ArrayList<Object> str = strExecute(expression);
//将表达式转换成后缀表达式
ArrayList<Object> suffixEx = convert(str);
//链表转换成队列,运算时需要用到队列
Queue<Object> queue = list2Queue(suffixEx);
//返回运算结果
return calculation(queue);
}
}
大功告成,去试试吧!