一、什么是逆波兰表达式
我们正常的计算表达式时这样的:(10*(9-5)+10)/2=25,这个叫中缀表达式,这样的话我们必须要判断优先级,当然对于我们来说判断优先级不是问题,但是对于计算机而言,却很麻烦。
那么如何不判断优先级呢,完全按从左到右进行计算,就是这样:
String[] expression={“10”,“9”,“5”,"-","",“10”,"+",“2”,"/"};主要思想就是,表达式前面的两个元素进行计算,然后结果整合为一个数,遇到表达式再计算,结果再放回去,从左到右,比如上面的表达式,先计算9-5=4,然后计算104=40,再计算40+10=50,最后50/2=25。
二、思路
- 循环遍历逆波兰表达式,如果不是运算符就装入栈
- 如果式运算符,就依次弹出两个元素pop1,pop2,运算pop2运算符pop1, 注意因为入栈时候pop2先入栈,pop1后入栈,因此要pop2运算符pop1,不能pop1运算符pop2
- 然后将运算的结果再入栈,继续上面的步骤
- 最后,循环完,取出栈中的元素就是最后的运算结果了
三、代码实现
/**
* 求解逆波兰表达式
* 先创建栈类
* 然后创建计算方法
* 最后测试
*
* 特别注意
* 因为入栈时候pop2先入栈,pop1后入栈,因此要pop2运算符pop1,不能式pop1运算符pop2
*/
package mypackage;
import java.util.Iterator;
//栈类
class Stack<T> implements Iterable<T> {
//节点类
private static class Node<T> {
T data;
Node next;
//构造方法
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
// 成员变量,头节点,节点个数
Node head;
int N;
// 构造方法
public Stack(){
// 初始head不指向任何节点,元素个数为零
this.head=new Node(null,null);
this.N=0;
}
// 节点个数
public int size(){
return N;
}
// 是否为空
public boolean isempty (){
return N==0;
}
// 压栈,即向链表中添加元素,注意因为栈是先进后出,每次添加节点应该都是添加在首节点后,再让新节点指向之前的第一个节点
// 第一次添加元素是让首节点指向新节点,接着再添加节点,就要让首节点指向新节点,新节点指向之前的第一个节点,依次类推
public void push(T data){
if (N==0){
Node newnode=new Node(data,null);
head.next=newnode;
N++;
}
else {
Node oldfirst=head.next;
Node newnode=new Node(data,null);
head.next=newnode;
newnode.next=oldfirst;
N++;
}
}
// 出栈
// 如果为空,则弹出null,
// 如果不为空,弹出head后的第一个元素,让head指向第二个元素
public T pop() {
Node oldfirst = head.next;
if (oldfirst==null) {
return null;
}
else {
head.next = oldfirst.next;
N--;
return (T) oldfirst.data;
}
}
// 重写,用于遍历
@Override
public Iterator<T> iterator() {
// 返回的Iterator对象,创建一个内部类实现这个接口
return new SIterator();
}
// 创建一个内部类实现Iterator接口
public class SIterator implements Iterator {
// 定义一个遍历的节点
private Node n;
public SIterator(){
// 初始化为0索引位置
this.n=head;
}
//重写两个方法
@Override
public boolean hasNext() {
// 这个方法判断是否超出最大索引,如果超出会停止遍历
return n.next!=null;
}
@Override
public Object next() {
// 这个方法会遍历得每个节点
n=n.next;
return n.data;
}
}
}
//测试
public class MyJava {
// 逆波兰表达式求解方法
// 循环遍历逆波兰表达式,如果不是运算符就装入栈
// 如果式运算符,就依次弹出两个元素pop1,pop2,运算pop2运算符pop1
// 注意因为入栈时候pop2先入栈,pop1后入栈,因此要pop2运算符pop1,不能pop1运算符pop2
// 然后将运算的结果再入栈,继续上面的步骤
// 最后,循环完,取出栈中的元素就是最后的运算结果了
private static int calculate(String[] expression) {
Stack<Integer> stack=new Stack<>();
// 先定义变量
Integer pop1;
Integer pop2;
Integer result;
// 开始循环
for (int i=0;i<expression.length;i++){
String exp=expression[i];
// 最好使用swith
switch (exp){
// 如果是+
case "+":
pop1=stack.pop();
pop2=stack.pop();
result=pop2+pop1;
stack.push(result);
break;
case "-":
pop1=stack.pop();
pop2=stack.pop();
result=pop2-pop1;
stack.push(result);
break;
case "*":
pop1=stack.pop();
pop2=stack.pop();
result=pop2*pop1;
stack.push(result);
break;
case "/":
pop1=stack.pop();
pop2=stack.pop();
result=pop2/pop1;
stack.push(result);
break;
// 如果不是运算符
default:
// 注意将String转化为Integar的方法Integer.parseInt
stack.push(Integer.parseInt(exp));
}
}
// 最后弹出的值就是结果
return stack.pop();
}
public static void main(String[] args) {
// 逆波兰表达式(10*(9-5)+10)/2=25
String[] expression={"10","9","5","-","*","10","+","2","/"};
System.out.println("逆波兰表达式结果为:"+calculate(expression));
}
}
结果: