【Algorithm】逆波兰表达式 Java实现

简介

逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。

逆波兰表达式可以用于表达式转换,如数学公式转换计算,很早之前做过一个计算器,但是解析公式 到时候感到万分头疼,今天看到逆波兰表达式这个东西,不禁感慨:

竟然还有这种操作

果然,数据结构学不好是得吃大亏。

思路

对于常规的数学表达式,我们要做的是根据其优先级计算结果(小学生都知道)。

编程实现的话,其实也很简单,两个栈即可实现,姑且把一个栈叫做 operators,保存运算符,另一个栈叫做output,保存最终的表达式。

就三个要点:

  • 数字直接入output
  • 运算符要与operators栈顶比较,优先级大则入栈,小于或等于则operators出栈后再入栈
  • operators栈顶若是(则无条件入栈

这里写图片描述

下面举的这个例子,只针对简单 + - * / ( ),别的实现,如小数,平方等操作,原理都差不多,可以自行扩展。

对这个a*(b-c*d)+e式子来说,转成波兰表达式后应该是这样子的:abcd*-*e+

1.读到a,将a压入output

这里写图片描述

2.读到*operators栈为空,直接将*压入operators

这里写图片描述

3.读到(优先级最高,无条件压入operators

这里写图片描述

4.读到b,将b压入output

这里写图片描述

5.读到-,因为有(的存在,无视比之前的*(优先级低

这里写图片描述

6.读到c,将c压入output

这里写图片描述

7.读到*,因为比+的优先级高,压入operators

这里写图片描述

8.读到d,将d压入output

这里写图片描述

9.读到),将operators(之后的所有运算符弹出并压入output

这里写图片描述

10.读到+,将operators所有栈顶优先级比+的运算符弹出,最后将+压入operators

这里写图片描述

11.读到e,将e压入output

这里写图片描述

12.表达式读取完,将output所有运算符压入output

这里写图片描述

实现

以下代码是Java的实现,字符串解析和逆波兰表达式解析放在一起,但还是根据上面的思路来解决。


import java.util.Stack;

public class ReversePolishNotation {
    public static void main(String[] args) {
        //测试用例
        //String str = "1+2*3-4*5-6+7*8-9"; //123*+45*-6-78*+9-
        String str = "a*(b-c*d)+e-f/g*(h+i*j-k)"; // abcd*-*e+fg/hij*+k-*-
        //String str = "6*(5+(2+3)*8+3)"; //6523+8*+3+*
        //String str = "a+b*c+(d*e+f)*g"; //abc*+de*f+g*f

        Stack<Character> operators = new Stack<>(); //运算符
        Stack output = new Stack(); //输出结果
        rpn(operators, output, str);
        System.out.println(output);
    }

    public static void rpn(Stack<Character> operators, Stack output, String str) {
        char[] chars = str.toCharArray();
        int pre = 0;
        boolean digital; //是否为数字(只要不是运算符,都是数字),用于截取字符串
        int len = chars.length;
        int bracket = 0; // 左括号的数量

        for (int i = 0; i < len; ) {
            pre = i;
            digital = Boolean.FALSE;
            //截取数字
            while (i < len && !Operator.isOperator(chars[i])) {
                i++;
                digital = Boolean.TRUE;
            }

            if (digital) {
                output.push(str.substring(pre, i));
            } else {
                char o = chars[i++]; //运算符
                if (o == '(') {
                    bracket++;
                }
                if (bracket > 0) {
                    if (o == ')') {
                        while (!operators.empty()) {
                            char top = operators.pop();
                            if (top == '(') {
                                break;
                            }
                            output.push(top);
                        }
                        bracket--;
                    } else {
                        //如果栈顶为 ( ,则直接添加,不顾其优先级
                        //如果之前有 ( ,但是 ( 不在栈顶,则需判断其优先级,如果优先级比栈顶的低,则依次出栈
                        while (!operators.empty() && operators.peek() != '(' && Operator.cmp(o, operators.peek()) <= 0) {
                            output.push(operators.pop());
                        }
                        operators.push(o);
                    }
                } else {
                    while (!operators.empty() && Operator.cmp(o, operators.peek()) <= 0) {
                        output.push(operators.pop());
                    }
                    operators.push(o);
                }
            }

        }
        //遍历结束,将运算符栈全部压入output
        while (!operators.empty()) {
            output.push(operators.pop());
        }
    }
}

enum Operator {
    ADD('+', 1), SUBTRACT('-', 1),
    MULTIPLY('*', 2), DIVIDE('/', 2),
    LEFT_BRACKET('(', 3), RIGHT_BRACKET(')', 3); //括号优先级最高
    char value;
    int priority;

    Operator(char value, int priority) {
        this.value = value;
        this.priority = priority;
    }

    /**
     * 比较两个符号的优先级
     *
     * @param c1
     * @param c2
     * @return c1的优先级是否比c2的高,高则返回正数,等于返回0,小于返回负数
     */
    public static int cmp(char c1, char c2) {
        int p1 = 0;
        int p2 = 0;
        for (Operator o : Operator.values()) {
            if (o.value == c1) {
                p1 = o.priority;
            }
            if (o.value == c2) {
                p2 = o.priority;
            }
        }
        return p1 - p2;
    }

    /**
     * 枚举出来的才视为运算符,用于扩展
     *
     * @param c
     * @return
     */
    public static boolean isOperator(char c) {
        for (Operator o : Operator.values()) {
            if (o.value == c) {
                return true;
            }
        }
        return false;
    }
}

源代码:
https://github.com/pingcai/Algorithm/tree/master/src/algorithm/ReversePolishNotation.java

参考

数据结构与算法分析-Java语言描述(P67)

https://zh.wikipedia.org/wiki/%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E7%A4%BA%E6%B3%95

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
海鸥优化算法(Seagull Optimization Algorithm)是一种基于鸥群行为的优化算法,模拟海鸥觅食的行为来寻找最优解。它以鸥群的协作和通信为基础,通过合理的搜索策略来解决优化问题。 该算法的主要特点包括两个方面:搜索过程中的多样性和引导搜索的能力。多样性指的是算法中适应度较高和较低的个体之间的差异性,保持种群中的多样性可以增加搜索空间的探索能力。而引导搜索的能力则是通过一种策略,将种群中的个体引导向更优的搜索空间。 在Java语言中,可以利用编程技巧来实现海鸥优化算法。首先,需要定义鸥(seagull)类,包括鸥的坐标、速度、适应度等属性。然后,初始化种群,包括生成鸥的初始位置和速度等信息。接下来,根据适应度函数计算每只鸥的适应度值,并更新种群的最优解和最优适应度值。 之后,通过迭代过程,按照一定的概率更新鸥的速度和位置,以期望找到更优的解。在迭代过程中可以使用一些改进策略,例如交叉、变异或局部搜索等,以提高算法的收敛性和搜索能力。 最后,在满足停止条件的情况下,输出最优解和最优适应度值。通过调整参数和改进算法,可以提高算法的性能和搜索结果。 总之,海鸥优化算法是一种基于鸥群行为的优化算法,可以通过编程实现,并在Java语言中进行应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值