利用逆波兰表达式(后缀表达式),实现简易计算器
实现功能:将中缀表达式转化为后缀表达式,进行基本的加减乘除操作,数字为多位整数,包含括号
实现思路:
1.输入一个逆波兰表达式 (3+4)*5-6 ——> 逆波兰表达式 3 4 + 5 * 6 -
将中缀表达式转换为逆波兰表达式,输入字符串,从左至右依次判断,
1.1 定义一个字符串,定义 index ,记录遍历的数字 使用StringBuilder 进行拼接 字符+空格
遇到数字,继续判断下一个是否为数字,若是,进行字符串拼接。若不是,将遍历的字符串存放在数组中。
1.2 定义一个符号栈 AuxiliaryStack (辅助栈)
遇到符号。若栈为空,符号入栈
若栈不为空,当前符号和栈顶符号进行比较,若当前符号的优先级高于栈顶符号的优先级,入符号栈
若当前符号的优先级低于等于栈顶符号的优先级,弹出栈顶元素并输出存放在数组中,当前元素继续和新的栈顶元素进行比较
左括号,直接压入堆栈(括号是最高优先级,无需比较)(入栈后优先级降到最低,确保其他符号正常入栈)
右括号,(意味着括号已结束)不断弹出栈顶运算符并输出直到遇到左括号(弹出但不输出)
若遍历完字符串,栈中依旧有元素,将栈中元素依次弹出,存放在数组中
2.计算逆波兰表达式
2.1 遍历字符串,遇到运算数,数字压入栈 numStack,
2.2 遇到符号,栈中弹出两个数字,次栈元素 运算符 栈顶元素 ,计算结果存入栈中,继续遍历。最后的结果即为计算结果
代码实现:
import java.util.Stack;
public class CountPalishCalculator {
// TODO: 2021/9/3
/**
* 输入一个逆波兰表达式(后缀表达式),使用栈Stack ,计算出其结果
*/
private static final int INITSIZE = 10;
/**
* 判断输入的字符为操作符还是运算符
* @param value 输入的字符
* @return
*/
public static boolean isSymbol(char value){
return value == '+' || value == '-' || value == '*' || value == '/' || value =='(' || value == ')';
}
/**
* 根据提供的字符判断其优先级大小,优先级越高,返回值越大
* @param symbol
* @return
*/
public static int priority(char symbol){
if(symbol == '*' || symbol == '/'){
return 2;
}else if(symbol == '+' || symbol == '-'){
return 1;
}else if(symbol == '(' ){
// 入栈 并将优先级降到最低
return 0;
}else{
return -1; // 输入有误
}
}
/**
* 加减乘除的计算方式
* @param num1 栈顶运算值
* @param num2 次顶运算值
* @param symbol 操作符
* @return
*/
public static float countMethod(float num1, float num2, char symbol){
float res = 0;
switch (symbol){
case('+'):
res = num1 + num2;
break;
case('-'):
res = num2 - num1;
break;
case('*'):
res = num1 * num2;
break;
case('/'):
res = num2 / num1;
break;
default:
break;
}
return res;
}
/**
*将输入的中缀表达式转化为 后缀表达式 存放在stringBuilder1 中
* @param str 输入的中缀表达式
* @return
*/
public static StringBuilder postfixNotation(String str){
int index = 0; // 记录遍历的顺序
char ch = 0; // 用来存放遍历的字符
StringBuilder stringBuilder1 = new StringBuilder();
Stack AuxiliaryStack = new Stack(); // 辅助栈
char symbol = 0; // 表示弹出的栈顶元素
while(true) {
ch = str.substring(index, index + 1).charAt(0);// 遍历字符串的字符
if(isSymbol(ch) == true){ // 字符为符号,入栈
if(AuxiliaryStack.isEmpty()){ // 若栈为空,则直接入栈
AuxiliaryStack.push(ch);
index++;
}else{
if(ch == '('){ // 左括号:直接压入堆栈(括号是最高优先级,无需比较)(入栈后优先级降到最低,确保其他符号正常入栈)
AuxiliaryStack.push(ch);
}else if(ch == ')'){ // 不断弹出栈顶运算符并输出直到遇到左括号(弹出但不输出)
while(true){
if((char)AuxiliaryStack.peek() == '('){ // 遇到左括号,左括号输入但不弹出
AuxiliaryStack.pop();
break;
}
stringBuilder1.append(AuxiliaryStack.pop()); // 未遇到左括号,输出并保存到stringBuilder1中
stringBuilder1.append(" ");
}
index++;
}else {
// 若栈不为空,当前符号和栈顶符号进行比较,若当前符号的优先级高于栈顶符号的优先级,入符号栈
// 若当前符号的优先级低于等于栈顶符号的优先级,弹出栈顶元素并输出存放在数组中,当前元素继续和新的栈顶元素进行比较
while (true) {
// 判断输出参数是否正确
if(priority(ch) < 0 || (!AuxiliaryStack.isEmpty()&&priority((char) AuxiliaryStack.peek())<0)){
System.out.println("符号输入错误");
break;
}
// 当前运算符和栈顶元素比较优先级,当栈为空时,当前运算符为唯一的运算符,无法比较,则直接入栈即可
if(AuxiliaryStack.isEmpty()){
AuxiliaryStack.push(ch);
index++;
break;
}
int num1 = priority(ch); // 当前符号的优先级
int num2 = priority((char) AuxiliaryStack.peek()); // 当前栈的栈顶元素的优先级,但不弹出
if (num1 > num2) {
AuxiliaryStack.push(ch);
index++;
break;
} else {
symbol = (char) AuxiliaryStack.pop(); //弹出栈顶元素
stringBuilder1.append(symbol);
stringBuilder1.append(" ");
}
}
}
}
}else { // 字符为数字 ,存入数组中
// 遇到数字,判断数字是否为最后一个字符,若是,该字符存入数组中;
// 若不是,继续判断下一个是否为数字,若是,进行字符串拼接。若不是,将遍历的字符串存放在数组中。
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(ch);
if(index == str.length()-1){ // 判断是否为最后一个字符 ,若是,直接拼接到stringBuilder中
stringBuilder1.append(stringBuilder);
stringBuilder1.append(" ");
index++;
}else {
while (true) {
// 第一个字符不是字符串的最后一个字符,通过while循环判断下一个字符是否为数字,
// 一直到最后一个字符,也是数字,拼接到stringBUilder中
if(index == str.length()-1){
stringBuilder1.append(stringBuilder);
stringBuilder1.append(" ");
index++;
break;
}
// 判断下一个字符是否为数字
ch = str.substring(index + 1, index + 2).charAt(0);
if (isSymbol(ch) == true) { // 若是符号,直接拼接
stringBuilder1.append(stringBuilder);
stringBuilder1.append(" ");
index++;
break;
}
stringBuilder.append(ch); // 若不是,继续判断并拼接
index++;
}
}
}
// 判断字符串是否遍历完,若遍历完,则输出辅助栈中存放的符号,直至栈空
if(index >= str.length()){
while (true){
if(AuxiliaryStack.isEmpty()){
break;
}
char symbol1 = (char)AuxiliaryStack.pop();
stringBuilder1.append(symbol1);
stringBuilder1.append(" ");
}
break;
}
}
return stringBuilder1;
}
// 2.1 遍历字符串,遇到运算数,数字压入栈 numStack,
// 2.2 遇到符号,栈中弹出两个数字,次栈元素 运算符 栈顶元素 ,计算结果存入栈中,继续遍历。最后的结果即为计算结果
public static float Method(String str){
float num1 = 0; // 栈顶操作数
float num2 = 0; // 次顶操作数
float result = 0;
Stack numStack = new Stack();
// 遍历字符串
for(int i = 0;i<str.length();i++){
if(isSymbol(str.charAt(i)) == false && str.charAt(i) != ' '){ // 不是符号也不是空格,为数字
StringBuilder Keep = new StringBuilder();
Keep.append(str.charAt(i));
int count = i;
// 遍历当前字符串的下一个字符
for(int j = count+1;j<str.length();j++){
if(isSymbol(str.charAt(j)) == false && str.charAt(j) != ' ') { // 为数字
Keep.append(str.charAt(j));
i++;
}else{
break;
}
}
String s = Keep.toString(); // StringBuilder转化为String类型
numStack.push(Float.parseFloat(s)); // String类型转化为float类型
}else if(str.charAt(i) ==' '){ // 是空格
continue;
}else if (isSymbol(str.charAt(i))){ // 若为符号,进行加减乘除基本操作
if(numStack.peek() instanceof Float){
num1 = (Float) numStack.pop();
num2 = (Float) numStack.pop();
}
char symbol = str.charAt(i);
result = countMethod(num1,num2,symbol);
numStack.push(result);
}
}
return result;
}
public static void main(String[] args) {
String str = "(3+40)*5-62";
StringBuilder s1 = postfixNotation(str);
String s = s1.toString();
float res1 = Method(s);
System.out.println("(3+40)*5-62 = "+res1);
}
}