数据结构与算法java - 07 中缀表达式 前缀表达式 后缀表达式 逆波兰表达式 逆波兰计算器 中缀表达式转为逆波兰表达式

前缀表达式

Prefix expression 波兰表达式,运算符都位于操作数之前

从右向左扫描表达式,遇到数字时,将数字压入堆栈;遇到运算符时,弹出栈顶的两个数,用运算符对他们做相应的计算(栈顶元素和次顶元素),并将结果入栈,重复上述过程直到表达式的最左端


举例:(3+4)×5-6 prefix expression: -×+3456

从右向左扫描,将 6,5,4,3 压入栈

遇到 + 弹出 3、4,计算 3+4 得到7,将 7 入栈

接下来是 ×,弹出 7、5,计算 7 × 5,将 35 入栈

最后是 - , 计算 35-6,即 29,得到最终结果


中缀表达式

常见的运算表达式;人熟悉,但是对于计算器来说不好操作


后缀表达式(逆波兰表达式)

suffix expression 运算符位于操作数之后

举例

(3+4)×5-6 的后缀表达式为 3 4 + 5 × 6 -

从左向右扫描表达式,遇到数字,将数字压入堆栈,遇到运算符,弹出栈顶的两个数,用运算符对他们做相应的计算(次顶元素和栈顶元素),将结果入栈,重复上述过程直到表达式最右端,得到结果

  • 从左向右扫描,将3、4压入堆栈

  • 遇到 +,弹出3、4,计算 3+4,得 7,将 7 入栈

  • 将 5 入栈

  • 接下来是 ×运算符,弹出 5、7, 计算 5 × 7,将 35 入栈

  • 将 6 入栈

  • 最后是 - 运算符,计算 35 - 6,即 29,得到结果


逆波兰计算器

要求

输入一个逆波兰计算器,使用栈,计算结果

支持小括号和多位数整数


思路

  1. 先将后缀表达式放入 ArrayList 中
  2. 将 ArrayList 传递给一个方法,配合栈完成计算

代码实现

package stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {
    public static void main(String[] args) {
        // define a suffix expression
        // use space split number and oper
        // (3+4)*5-6
        String suffixExpression = "3 4 + 5 * 6 -";
        // 1. put expression into arraylist
        // 2. transfer Arraylist to a method, do calculate with stack
        List<String> rpnList = getListString(suffixExpression);
        System.out.println("rpnList"+rpnList);
        int res = calculate(rpnList);
        System.out.println("result is: " + res);
    }

    // put nums and opers of suffix expression into an ArrayList by order
    public static List<String> getListString(String suffixExpression){
        // split suffix expression
        String[] split = suffixExpression.split(" ");
        List<String> list = new ArrayList<String>();
        for(String ele:split){
            list.add(ele);
        }
        return list;
    }

    // calculation
    public static int calculate(List<String> ls){
        // create one stack
        Stack<String> stack = new Stack<>();
        // traverse ls
        for (String item : ls) {
            // pick up number using regular expression
            if (item.matches("\\d+")) { // match multiple digits
                // push
                stack.push(item);
            } else {
                // pop two nums and calculate, then push
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;
                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("have something wrong");
                }
                // push res
                stack.push("" + res);
            }
        }
        // the data left in stack is the result
        return Integer.parseInt(stack.pop());
    }
}

中缀表达式转后缀表达式

步骤分析

  1. 初始化两个栈,运算符栈 s1 和存储中间结果的栈 s2

  2. 从左至右扫描中缀表达式

  3. 遇到操作数时,将其压入 s2

  4. 遇到运算符时,比较其与 s1 栈顶运算符的优先级

    1. 如果 s1 为空,或栈顶运算符为左括号 ”(“,则直接将此运算符入栈

    2. 否则,若优先级比栈顶运算符的高,也将运算符压入 s1

    3. 否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到 4.1与 s1 中的新的栈顶运算符比较

  5. 遇到括号时

    1. 如果是左括号 “(”,则直接压入 s1
    2. 如果是右括号 ”)“,则依次 弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃
  6. 重复步骤 2-5,直到表达式的最右边

  7. 将 s1 中剩余运算符依次弹出压入 s2

  8. 依次弹出 s2 中的元素并输出,结果的逆序即为中缀表达式的后缀表达式


代码实现

思路

因为直接对 string 进行操作不方便,先将中缀表达式转为对应的 list

    // transfer infix expression to list
    public static List<String> InfixToList(String s){
        // define a list
        List<String> ls = new ArrayList<>();
        int i = 0; // pointer for traversing infix string
        String str; // aiming to splice multiple digit
        char c; // put each char into c
        do{
            // if c is not a num, join it to ls
            if((c=s.charAt(i))<48 || (c=s.charAt(i))>57){ // range of num
                ls.add(""+c);
                i++;
            }else{
                // if c is a num, considering multi digits
                str = ""; // default ""
                while(i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
                    str+=c;
                    i++;
                }
                ls.add(str);
            }
        }while(i<s.length());
        return ls;
    }

将得到的中缀表达式对应的 list 转换为后缀表达式对应的 list

存放中间结果的栈没有 pop 操作,并且需要逆序数处,因此在这里不使用 栈 结构,而是使用 ArrayList


返回优先级的类

// oper : return priority of a oper
class Operation{
    private static int ADD = 1;
    private static int  SUB = 1;
    private static int  MUL = 2;
    private static int  DIV = 2;
    // METHOD RETURN THE PRIORITY VALUE
    public static int getValue(String operation){
        int result = 0;
        switch (operation){
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = MUL;
                break;
            case "/":
                result = DIV;
                break;
            default:
                System.out.println("oper not exists");
                break;
        }
        return result;
    }
}

中缀表达式对应的 list 转为后缀表达式对应的 list

public static List<String> parseSuffixExpressionList(List<String> ls){
        // define two stack
        Stack<String> s1 = new Stack<>(); // stack for symbol
        List<String> s2 = new ArrayList<>(); // store intermediate result
        // traverse ls
        for(String item:ls){
            // if item is a num, add to s2
            if(item.matches("\\d+")){
                s2.add(item);
            }else if(item.equals("(")){
                s1.push(item);
            }else if(item.equals(")")){
                while(!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop(); // !!! pop "(" from s1
            }else{
                // if item's priority smaller than/ equals to s1  stack top
                // pop top element from s1 and add it to s2
                // lack a method comparing priority of oper
                while(s1.size()!=0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                // push item to s1
                s1.push(item);
            }
        }
        // add opers left in s1 into s2
        while(s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2; // due to using list storing data, so data print out is the correct order

    }

test main()

        String expression = "(3+4)*5-6";
        List<String> infixEpressionList = InfixToList(expression);
        System.out.println(infixEpressionList);
        List<String> SuffixExpressionList = parseSuffixExpressionList(infixEpressionList);
        System.out.println("infix: "+expression+" suffix: "+SuffixExpressionList);
        System.out.println(calculate(SuffixExpressionList));
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值