JAVA数据结构与算法-前缀、中缀、后缀表达式


例:计算(3+4)*5-6。

前缀、中缀、后缀表达式

  • 一.前缀表达式(波兰表达式):
  • 二.中缀表达式:
  • 三.后缀表达式(逆波兰表达式):
  • 四.逆波兰计算器
  • 五.中缀表达式转后缀表达式
    • 1.步骤
    • 2.注意:
    • 3.程序

一.前缀表达式(波兰表达式):

表达式为:-*+3456。

计算机求值步骤:从右向左扫描,遇到数字时压入堆栈,遇到运算符时弹出栈顶的两个数字,使用运算符进行运算(若为-则计算表达式为栈顶元素-次顶元素),并将结果入栈,一直进行到表达式最左端。

运算顺序:先按顺序将所有数字入栈,再根据表达式的计算顺序逐个运算符计算。

二.中缀表达式:

与平常顺序相同,为(3+4)*5-6,对计算机来说不好操作,需要判断计算优先级,通常会转为其他表达式。

三.后缀表达式(逆波兰表达式):

表达式为34+5*6-。

计算机求值步骤:与前缀表达式相似,运算符位于操作符之后。计算时从左向右扫描,扫描到数字则入栈,扫描到操作符则弹出栈顶的两个元素进行运算(若为-则计算表达式为次顶元素-栈顶元素),并将结果入栈,一直到表达式最右端。

特点:若出现多个数字间无操作符,则代表有小括号;数字与中缀表达式顺序一致;通常在两个数字之后会有一个操作符表示这两个数字的操作。

实例:

                 正常表达式                                                           逆波兰表达式

                       a+b                                                                       ab+

                    a+(b-c)                                                                   abc-+

                   a+(b-c)*d                                                                adbc-*+

                    a=1+3                                                                    a13+=

四.逆波兰计算器

class PolandCalculator {
    public ArrayList arr;
    public Stack stack = new Stack<>();  

    public boolean isDigit(String sub) {  // 判断该字符串是否全为数字,返回值为boolean
        boolean flag = true;
        for (int i = 0; i < sub.length(); i++) {
            char ch = sub.charAt(i);
            if (ch > 57 || ch < 48) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    public int cal(int num1, int num2, int operate) {  // 定义将运算符和数pop后计算的过程,输入均为int,运算符以char类型保存,其int值为ASCII码值,输出为计算结果
        int res = 0;
        switch (operate) {
            case '+' -> res = num2 + num1;
            case '-' -> res = num2 - num1;
            case '*' -> res = num2 * num1;
            case '/' -> res = num2 / num1;
            default -> {
            }
        }
        return res;
    }

    public int calculate(String expression) {  // 计算表达式的值,输入为字符串类型的表达式,各数字与运算符间使用空格分隔
        arr = new ArrayList<>();
        String[] str = expression.split(" ");
        arr.addAll(Arrays.asList(str));  // 字符串数组转ArrayList
        for (String s : arr) {
            if (isDigit(s)) stack.push(Integer.parseInt(s));  // 若为数字则入栈
            else {  // 若为运算符则弹出两个数,进行运算后入栈
                int num1 = stack.pop();
                int num2 = stack.pop();
                int res = cal(num1, num2, s.charAt(0));
                stack.push(res);
            }
        }
        return stack.pop();
    }
}

五.中缀表达式转后缀表达式

1.步骤

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

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

  3. 遇到数字时压入s2.

  4. 遇到运算符时,比较其与s1栈顶运算符的优先级
    4.1若s1为空,或栈顶运算符为"(",则将此运算符入栈。
    4.2若该运算符优先级比栈顶运算符高,则将此运算符入栈。
    4.3否则,将s1栈顶运算符弹出并压入s2,回到4.1与新的栈顶运算符作比较。

  5. 遇到括号时,"(“直接压入s1,”)"则依次弹出s1中的运算符并压入s2,之后舍弃这对括号。

  6. 重复步骤2-5,直到表达式最右边。

  7. 将s1中剩余运算符压入s2.

  8. 依次弹出s2中的元素,其逆序即为后缀表达式。

2.注意:

(1)首次扫描到运算符时要么压入s1(该运算符优先级较高),要么将其他运算符弹出后压入s1(该运算符优先级较低),在扫描到优先级更低的运算符或全部扫描完成后压入s2,因此在运算的数之后。
(2)不考虑括号的情况下,"*/“会比"±"更先压入s2,且位置就在其操作数后面。
(3)括号中的数和操作符会在扫描到”)"时压入s2,比括号外更早压入,因此更早执行。

3.程序

​`class PolandCalculator {
public ArrayList arr;
public Stack s1 = new Stack<>(); // 保存符号的栈
public Stack s2 = new Stack<>(); // 保存中间变量的栈

public int priority(int operate) {  // 定义运算符优先级,*/大于+-
    int res = -1;
    switch (operate) {
        case '*', '/' -> res = 2;
        case '+', '-' -> res = 1;
        case '(' -> res = 0;
        default -> {}
    }
    return res;
}

public ArrayList gen_expression(String expression) {  // 提取中缀表达式中的各项,并转为后缀表达式
    arr = new ArrayList<>();
    int index = -1;
    for (int i = 0; i < expression.length(); i++) {
        char ch = expression.charAt(i);
        if (ch >= 48 && ch <= 57) {
            if (index == -1) index = i;  // 前一位不是数字,这一位是数字,设置此数字的起始索引
        }
        else {
            if (index != -1) {
                arr.add(expression.substring(index, i));  // 数字结束,将其加入到ArrayList中
                index = -1;  // 此数字扫描结束,index设置成初值
            }
            if (ch == ' ') continue;;
            arr.add(ch + "");
        }
        if (i == expression.length() - 1) arr.add(expression.substring(index, i + 1));
    }
    // 将表达式转为后缀表达式
    for (String str : arr) {
        if (isDigit(str)) {
            s2.push(str);  // 若是数字则直接压入s2
        }
        else {  // 若是运算符
            char ch = str.charAt(0);
            if (s1.isEmpty() || ch == '(') s1.push(ch + "");  // s1为空或该符号为"("时直接压入s1
            else if (ch == ')') {  // 若是")"则将"("之后的所有运算符压入s2
                char last_operate = s1.pop().charAt(0);
                while (last_operate != '(') {
                    s2.push(last_operate + "");
                    last_operate = s1.pop().charAt(0);
                }
            }
            else {
                boolean isMin = false;  // 指示当前运算符是否优先级最小
                char last_operate = s1.pop().charAt(0);  // 否则弹出s1栈顶的运算符
                while (priority(ch) <= priority(last_operate)) {  // 当前运算符优先级小于等于栈顶运算符时将栈顶运算符压入s2,再和下一个栈顶运算符比较
                    s2.push(last_operate + "");
                    if (s1.isEmpty()) {
                        isMin = true;
                        break;
                    }
                    last_operate = s1.pop().charAt(0);
                }
                if (!isMin) s1.push(last_operate + "");
                s1.push(ch + "");
            }
        }
    }
    while (!s1.isEmpty()) s2.push(s1.pop());
    arr.clear();
    while (!s2.isEmpty()) arr.add(0, s2.pop());
    return arr;
}

public boolean isDigit(String sub) {
    boolean flag = true;
    for (int i = 0; i < sub.length(); i++) {
        char ch = sub.charAt(i);
        if (ch > 57 || ch < 48) {
            flag = false;
            break;
        }
    }
    return flag;
}

public int cal(int num1, int num2, int operate) {  // 定义将运算符和数pop后计算的过程,输入均为int,输出为计算结果
    int res = 0;
    switch (operate) {
        case '+' -> res = num2 + num1;
        case '-' -> res = num2 - num1;
        case '*' -> res = num2 * num1;
        case '/' -> res = num2 / num1;
        default -> {
        }
    }
    return res;
}

public int calculate(String expression) {
    Stack stack = new Stack<>();
    ArrayList suffix_expression = gen_expression(expression);
    for (String s : suffix_expression) {
        if (isDigit(s)) stack.push(Integer.parseInt(s));
        else {
            int num1 = stack.pop();
            int num2 = stack.pop();
            int res = cal(num1, num2, s.charAt(0));
            stack.push(res);
        }
    }
    return stack.pop();
}

}`

你可能感兴趣的:(JAVA数据结构与算法,java,数据结构,开发语言)