逆波兰计算器原理
1.计算器的几种形式
- 前缀表达式:符号在前左,数字在右。符号数字位置考虑运算优先级。
- 中缀表达式 :符号在数字中间(即正常书写的表式结构 “1+( (2+3) *4)-5”
- 后缀 表达式:将要进行的部分运算的数字在前运算符号在后,接着其它部分的运算。
2.计算表达式分析
计算表达式一般包含数值,运算符,括号,包括运算符的优先级计算,以及括号产生的优先级运算。
3.栈的特点
- 先进后出
- 存和取出数据的方式适合优先级符号的存取
- 在while循环中,控制长度,栈的存和取可以使 迭代条件省去(i++)
4.不同显示的思路分析
4.1中缀实现的分析
-
几个要素:
- 两个栈 符号栈与数字栈
- 扫描方式以及识别的方法(多位数与单位数的区别、符号、运算符)
- 分别存入两个栈的要求
- 优先级可考虑(与上一个存入符号栈的优先级的比较)
- 数字栈最后一个数为结构
-
重点
- 符号栈必须要有一个符号,便于符号优先级的比较,通过比较扫描的与栈顶的符号优先级,如果栈顶优先级大于等于扫描到的,弹入数字栈。
- 遇到“( ” 与 “ )” 的区别,遇到“( ” 直接入栈,遇到” )“ ,将符号栈中符号依次弹出,直到”(“ 位置,将”(“ 消除即可。
-
/** * 中缀转后缀 说明:list为ArrayList对象, 数字站也是ArrayList对象。 * 1.一个符号栈,一个数字存储栈 * 2.逐个配对list对象内的变量从左到右 * 3.如果是数字 存入数字存储栈, * 4 .如果是括号 * > 1.如果符号栈空压入栈 * > 2.如果是"( "压入符号栈 * > 3.如果是括号")" ,一次弹出符号栈字符于数字存储栈,直到遇到"(", * 将"(" 弹出即可(删除,不用存入) * 5.如果是运算符 * 1.符号栈空直接添加即可 * 2.如果当前符号优先级小于等于栈顶优先级,将栈顶符号存入数字存储栈 * 然后重新步骤5(对于扫描的符号) * 6.扫描到了最右,将剩余符号栈的符号存入数字存储栈 */
5.代码
public class PolandNotation {
public static void main(String[] args) {
String suffixExpression = "30 4 + 5 * 6 -";
List<String> list = getList(suffixExpression);
System.out.println(list);
//遍历数组
int ans = caculate(list);
System.out.println("结果是:" + ans);
List<String> s1 = toInfixExpressionList("1*(2+3)*4-5");
System.out.println(s1);
List<String> s2 = toInfixExpressions(s1);
System.out.println(s2);
}
public static List<String> toInfixExpressions(List<String > list){
Stack<String> stack = new Stack<String>();
List<String> numlist = new ArrayList<String>();
for(String item : list){
System.out.println(item);
if(item.matches("\\d+")){//识别多位数
numlist.add(item);
}else if (item.equals("(")){
stack.push(item);
}else if (item.equals(")")){
while (!stack.peek().equals("(") ){//字符串对比用equals
numlist.add( stack.pop());
}
stack.pop();//消掉"("
}else {//由于符号类型多,可以放在else内
while (stack.size() != 0 && !stack.peek().equals("(") && Operation.getValue(stack.peek()) >= Operation.getValue(item)) {
numlist.add(stack.pop());
}
stack.push(item);
}
}
//将剩余stack栈符号存入数字列表
while(stack.size() != 0){
numlist.add(stack.pop());
}
return numlist;
}
/**
* 提取字符串为list
* 1.字符串输入
* 2.多位数的判断、符号的判断 48 - 57 字符'0' ---'9'
* 3.使用do while结构
*/
public static List<String> toInfixExpressionList(String s){
List<String> list = new ArrayList<>();
char c;
int i = 0;
String str;
do{
if(s.charAt(i) < 48 || s.charAt(i) > 57){//不为数字
list.add(""+s.charAt(i));
i++;
}else {
str ="";
while( i < s.length() && s.charAt(i) >= 48 && s.charAt(i) <= 57){
str += ""+s.charAt(i);
i++;
}
list.add(str);
}
}while(i < s.length());
return list;
}
public static int caculate(List<String> list){
Stack<String> stack = new Stack<>();
int num1 = 0;
int num2 = 0;
int res = 0;
for(String item : list ){
if (item.matches("\\d+")){//比配多位数
stack.push(item);
}else {
num2 = Integer.parseInt(stack.pop());
num1 = Integer.parseInt(stack.pop());
if (item.equals("*")){
res = num1 * num2;
}else if (item.equals("/")) {
res = num1 / num2;
}else if (item.equals("+")) {
res = num1 + num2;
}else if (item.equals("-")){
res = num1 - num2;
}else {
throw new RuntimeException("符号错误");
}
stack.push(""+res);
}
}
return res;
}
public static List<String> getList(String suffixExpression){
List<String> list = new ArrayList<>();
String[] str = suffixExpression.split(" ");
for(String value : str){
list.add(value);
}
return list;
}
}
class Operation{
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DEL = 2;
public static int getValue(String operation){
int res = 0;
if(operation.equals("*")){
res = MUL;
}else if (operation.equals("/")){
res = DEL;
}else if (operation.equals("+")){
res = ADD;
}else if (operation.equals("-")){
res = SUB;
}else {
System.out.println(operation);
System.out.println("符号错误---");
}
return res;
}
}