实现逆波兰计算器,主要通过以下三个步骤:
1. 将输入的字符串(表达式)按每个数值、操作符单独存储在字符串数组infix中。例如infix中的字符串可以是“-2.3333”、“1.2138”、“+”、“*”、“(”等等。
2. 通过栈和操作符的优先级的比较,将中缀表达式infix转换为后缀表达式postfix。
3. 通过栈,计算posfix的结果。
下面是具体实现的代码:
import java.util.*;
public class ReversePolishNotation{
private String ex; //输入表达式(未分割)
private String[] infix = new String[100];//存储中缀表达式
private String[] postfix = new String[100];//存储后缀表达式
public ReversePolishNotation(){}
/* 将表达式按数值和操作符进行分割 */
private void exSplit() {
int len = 0;
for(int i = 0 ; i < ex.length() ; i++) {
char c = ex.charAt(i);
int startIndex = i;
//负数
if( c == '-' && ( i == 0 || ex.charAt(i-1) < '0' || ex.charAt(i-1) > '9') ) {
do {
i++;
if(i == ex.length()){//已经超出了字符串末尾
break;
}
c = ex.charAt(i);
}while( (c >= '0' && c <= '9') || c == '.') ; //判断是否为非个位数或者小数
infix[len] = ex.substring(startIndex , i);//[startIndex,i)
len++;
i--;//continue无法忽略最后的i++
continue;
}
//正数
if(c >= '0' && c <= '9'){
do {
i++;
if(i == ex.length()){
break;
}
c = ex.charAt(i);
}while( (c >= '0' && c <= '9') || c == '.') ;
infix[len] = ex.substring(startIndex , i);
len++;
i--;
continue;
}
infix[len] = ex.substring(startIndex ,startIndex + 1);
len++;
}
}
/* 将中缀表达式变为后缀表达式 */
private void infixToPostfix(){
this.exSplit();
ArrayDeque stack = new ArrayDeque<>();
int i = 0;
for(String str:infix){
//最后将留在栈里的操作符依次出栈
if(str == null){
while(stack.peekFirst() != null) {
postfix[i++] = stack.pop();
}
break;
}
//注意:Java中字符串是引用类型,两个引用类型变量,只有他们指向同一个对象时,==判断才会返回true;String已经重写了Object的equals()方法,只要两个字符串所包含的字符序列相同,返回true。
if( !str.equals("(") && !str.equals(")") && !str.equals("+") && !str.equals("-")&& !str.equals("*") && !str.equals("/")){
postfix[i++] = str;
}
else {
String topStr = stack.peekFirst();
if(topStr == null){
stack.push(str);
continue;
}
switch(str){
//"("默认入栈,当待入栈的操作符为")"时,小括号之间的操作符依次出栈
case ")": {
while(!stack.peekFirst().equals("(")){
postfix[i++] = stack.pop();
}
stack.pop();//弹出'('
break;
}
//栈顶操作符优先级大于等于待入栈的操作符,栈顶的操作符需要先执行,因此出栈
//计算顺序为从左到右,所以优先级相等的时候,先入栈的先计算
case "*": {
//到栈顶的操作符优先级小于待入栈的操作符位置
while(topStr.equals("*") || topStr.equals("/") ){
postfix[i++] = stack.pop();
topStr = stack.peekFirst();
if(topStr == null){
break;
}
}
break;
}
case "/": {
while(topStr.equals("*") || topStr.equals("/") ){
postfix[i++] = stack.pop();
topStr = stack.peekFirst();
if(topStr == null){
break;
}
}
break;
}
case "+": {
while(topStr.equals("*") || topStr.equals("/") || topStr.equals("+") || topStr.equals("-") ){
postfix[i++] = stack.pop();
topStr = stack.peekFirst();
if(topStr == null){
break;
}
}
break;
}
case "-": {
while(topStr.equals("*") || topStr.equals("/") || topStr.equals("+") || topStr.equals("-")){
postfix[i++] = stack.pop();
topStr = stack.peekFirst();
if(topStr == null){
break;
}
}
break;
}
}
//")"不用入栈,用于匹配"("
if(!str.equals(")")){
stack.push(str);
}
}
}
}
/* 后缀表达式*/
public double calculate(String ex){
this.ex = ex;
this.infixToPostfix();
ArrayDeque stack = new ArrayDeque<>();
double popFirst,popSecond;
for(String str: postfix){
if(str == null){
break;
}
if( !str.equals("(") && !str.equals(")") && !str.equals("+") && !str.equals("-")&& !str.equals("*") && !str.equals("/")){
stack.push( Double.parseDouble(str) );
}
else{
switch(str){
case "*": {
popFirst = stack.pop();
popSecond = stack.pop();
stack.push(popSecond * popFirst);
break;
}
case "/": {
popFirst = stack.pop();
popSecond = stack.pop();
stack.push(popSecond / popFirst);
break;
}
case "+": {
popFirst = stack.pop();
popSecond = stack.pop();
stack.push(popSecond + popFirst);
break;
}
case "-": {
popFirst = stack.pop();
popSecond = stack.pop();
stack.push(popSecond - popFirst);
break;
}
}
}
}
return stack.pop();
}
/* 输出后缀表达式 */
private void outPostfix(){
for(String str:postfix){
if(str == null){
break;
}
System.out.print(str + " ");
}
System.out.println();
}
//测试
public static void main(String[] args) {
ReversePolishNotation rpn = new ReversePolishNotation();
System.out.println("计算结果:" + rpn.calculate("-1.23+2*(3.14+0+4.1*1*(-2*5+20)+3+3)*4--2.34"));
System.out.println("后缀表达式:");
rpn.outPostfix();
}
}