• 逆波兰算法-python代码实现


    1,逆波兰算法简介

    假定给定一个只 包含 加、减、乘、除,和括号的算术表达式,你怎么编写程序计算出其结果?

    问题是:在表达式中,括号,以及括号的多层嵌套 的使用,运算符的优先级不同等因素,使得一个算术表达式在计算时,运算顺序往往因表达式的内容而定,不具规律性。 这样很难编写出统一的计算指令。
    使用逆波兰算法可以轻松解决这个问题。他的核心思想是将普通的中缀表达式转换为后缀表达式。

    什么是中缀表达式?例如a+b,运算符在两个操作数的中间。这是我们从小学开始学习数学就一直使用的表达式形式。

    什么是后缀表达式?例如a b + ,运算符在两个操作数的后面。后缀表达式虽然看起来奇怪,不利于人阅读,但利于计算机处理。

    转换为后缀表达式的好处是:
    1、去除原来表达式中的括号,因为括号只指示运算顺序,不是实际参与计算的元素。
    2、使得运算顺序有规律可寻,计算机能编写出代码完成计算。

    2,逆波兰算法原理

    逆波兰算法的核心步骤就2个:
    1、将中缀表达式转换为后缀表达式,例如输入的原始表达式是 3*(5+7) ,转换得到 3 5 7 + *
    2、根据后缀表达式,按照特定的计算规则得到最终计算结果

    下面详细介绍这个2步的操作。

    中缀表达式转换为后缀表达式
    你需要设定一个栈SOP,和一个线性表 L 。SOP用于临时存储运算符和左括号分界符( ,L用于存储后缀表达式。
    遍历原始表达式中的每一个表达式元素
    (1)如果是操作数,则直接追加到 L中。只有 运算符 或者 分界符( 才可以存放到 栈SOP中
    (2)如果是分界符
             Ⅰ 如果是左括号 ( , 则 直接压入SOP,等待下一个最近的 右括号 与之配对。
              Ⅱ 如果是右括号),则说明有一对括号已经配对(在表达式输入无误的情况下)。不将它压栈,丢弃它,然后从SOP中出栈,得到元素e,将e依次追加到L里。一直循环,直到出栈元素e 是 左括号 ( ,同样丢弃他。
    (3)如果是运算符(用op1表示)
            Ⅰ如果SOP栈顶元素(用op2表示) 不是运算符,则二者没有可比性,则直接将此运算符op1压栈。 例如栈顶是左括号 ( ,或者栈为空。
             Ⅱ 如果SOP栈顶元素(用op2表示) 是运算符 ,则比较op1和 op2的优先级。如果op1 > op2 ,则直接将此运算符op1压栈。
    如果不满足op1 > op2,则将op2出栈,并追加到L,再试图将op1压栈,如果如果依然不满足 op1>新的栈顶op2,继续将新的op2弹出追加到L ,直到op1可以压入栈中为止。
    也就是说,如果在SOP栈中,有2个相邻的元素都是运算符,则他们必须满足:下层运算符的优先级一定小于上层元素的优先级,才能相邻。

    最后,如果SOP中还有元素,则依次弹出追加到L后,就得到了后缀表达式。

    3,应用

    请写一个整数计算器,支持加减乘除三种运算和括号。

    输入
    
    "1+2"
    
    输出
    
    3
    
    输入
    
    "(2*(3-4))*5"
    
    输出
    
    -10

    python 代码实现:

    class Solution:
        def __init__(self):
            self.Operator_priority = {
                "+": 0,
                "-": 0,
                "*": 1,
                "/": 1
            }
            self.Operator = ["+""-""*""/"]
            self.DemarcationSymbol = ["("")"]
            self.L = []
            self.stack = []
    
        def solve(self, s):
            self.infixToSuffix(s)
            return self.suffixToResult(self.L)
    
    
        def changeTypeofExpression(self, expression):
            temp_expression = []
            temp_num ""
            for exp in expression:
                if exp.isdigit():
                    temp_num += exp
                    continue
                else:
                    temp_expression.append(temp_num)
                    temp_num ""
                    temp_expression.append(exp)
            temp_expression.append(temp_num)
            return temp_expression
    
    
        def infixToSuffix(self, expression):
            temp_expression = self.changeTypeofExpression(expression)
            for item in temp_expression:
                if item.isdigit():
                    self.L.append(item)
                elif item in self.Operator:  # 判断是否是操作符
                    while len(self.stack) != 0 and self.stack[-1] in self.Operator and self.Operator_priority[item] <= self.Operator_priority[self.stack[-1]]:
                        self.L.append(self.stack.pop())
                    self.stack.append(item)
    
    
                elif item in self.DemarcationSymbol:  # 判断是否是分隔符
                    if item == "(":
                        self.stack.append(item)
                    elif item == ")":
                        while len(self.stack) != 0 and self.stack[-1] != "(":
                            self.L.append(self.stack.pop())
                        if len(self.stack) != 0:
                            self.stack.pop()
    
    
            while len(self.stack) != 0:
                self.L.append(self.stack.pop())
    
    
        def suffixToResult(self, suffix_expression):
            for item in suffix_expression:
                if item.isdigit():  # 如果是数字就添加到stack中去
                    self.stack.append(item)
                elif item in self.Operator:
                    num1 = self.stack.pop()
                    num2 = self.stack.pop()
                    temp_value = self.Calculation(float(num2), float(num1), item)
                    self.stack.append(temp_value)
            return self.stack.pop()
    
    
        def Calculation(self, num1, num2, op):
            if op == "+":
                return num1+num2
            elif op == "-":
                return num1-num2
            elif op == "*":
                return num1*num2
            else:
                return num1/num2
    
    
    if __name__ == "__main__":
        s = Solution()
        print(s.solve("(100+100)*100"))
    不论你在什么时候开始,重要的是开始之后就不要停止。 不论你在什么时候结束,重要的是结束之后就不要悔恨。
  • 相关阅读:
    tomcat源码springboot搭建的跑包含websocket的项目
    tomcat源码ant编译
    职责链设计模式最简单的实例
    完美解决asp.net core 3.1 两个AuthenticationScheme(cookie,jwt)共存在一个项目中
    基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式
    Html5 在手机端 input 默认弹出英文键盘
    Html Table 表格 画斜线
    多个单列索引和联合索引的区别
    springboot常用功能
    前端代码评审(Code Review)
  • 原文地址:https://www.cnblogs.com/yunhgu/p/13885680.html
Copyright © 2020-2023  润新知