• 栈实现简单四则运算


    栈是一种操作受限的线性表,只允许在一端插入或删除数据,后进先出,先进后出,就是典型的栈结构。

    栈主要包含2个操作,入栈和出栈,也就是在栈顶插入或删除一个元素。

    实现一个基于数组的顺序栈:

    class Stack:
        def __init__(self, cap=64):
            self.L = []
            self.cap = cap
            self.cnt = 0
    
        def push(self, data):
            if self.cnt == self.cap:
                return False
            self.L.append(data) 
            self.cnt += 1
            return True
    
        def pop(self):
            if self.cnt == 0:
                return None
            v = self.L.pop()
            self.cnt -= 1
            return v
    

    栈在表达式求值中的应用

    将表达式简化为只包含加、减、乘、除四则运算,例如:3 + 2 * 4 - 1,人脑可以迅速得出答案,但是对于计算机来说,理解这个表达式就是一件很难的事。

    我们可以使用2个栈,一个保存数据,另一个保存操作符,从左向右遍历表达式,当遇到数字就直接压入数据栈,遇到操作符时就与操作符栈顶元素比较:

    • 如果比栈顶操作符优先级高,直接将当前运算符入栈
    • 如果比栈顶元素优先级低或者相同,则从操作符栈取出元素,再从数据栈取出2个元素进行计算,结果保存到数据栈,然后继续比较

    用代码实现如下:

    class UnsupportExpressionError(Exception):
        pass
    
    
    class UnsupportOperationError(Exception):
        pass
    
    
    class SimpleCalculator:
        _priority = {
            '+': 10, '-': 10,
            '*': 20, '/': 20,
        }
        _digits = {
            '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, 
            '5': 5, '6': 6, '7': 7, '8': 8, '9': 9
        }
    
        def __init__(self, expression):
            self.symbol_stack = Stack()
            self.number_stack = Stack()
            self.expression = expression
            self._result = self.get_result()
    
        @property
        def result(self):
            return self._result
    
        def get_result(self):
            decimal = 0
            for x in self.expression:
                v = x.strip()
                if not v:
                    continue
                
                if v in self._priority:
                    self.number_stack.push(decimal)
                    decimal = 0
                    self.cmp_and_calc(v)
                    self.symbol_stack.push(v)
                elif v in self._digits:
                    decimal = decimal * 10 + self._digits[v]
                else:
                    raise UnsupportExpressionError(f'unsupport operation: "{v}" in expression: {self.expression}')
    
            self.number_stack.push(decimal)
            operation = self.symbol_stack.pop()
            while operation:
                ret = self._calc_helper(operation)
                self.number_stack.push(ret)
                operation = self.symbol_stack.pop()
            ret = self.number_stack.pop()
    
            return ret
    
        def cmp_and_calc(self, operation):
            symbol = self.symbol_stack.pop()
            if symbol is None:
                return
            if self._priority[operation] > self._priority[symbol]:
                self.symbol_stack.push(symbol)
            else:
                ret = self._calc_helper(symbol)
                self.number_stack.push(ret)
                self.cmp_and_calc(operation)
    
        def _calc_helper(self, operation):
            b = self.number_stack.pop()
            a = self.number_stack.pop()
            if a is None:
                return b
            
            if operation == '+':
                return a + b
            elif operation == '-':
                return a - b
            elif operation == '*':
                return a * b
            elif operation == '/':
                return a / b
            else:
                raise UnsupportOperationError(f'unsupport operation: {operation}')
    
    def main():
        s = ''
        while not s or not s.strip():
            s = input('please enter an expression: ')
        c = SimpleCalculator(s)
        print(c.result)
    
    

    带括号的表达式求值

    同理可以使用一个栈保存表达式,当遇到右括号时,将该括号对里面的表达式使用上面的 SimpleCalculator 计算,得出的结果再压入栈,最后得到的表达式就是一个不含括号的表达式了。

    例如表达式:2*(6/(1+2)) 计算过程:

    1. 将 '2*(6/(1+2' 依次入栈
    2. 遇到 ')' ,不断从栈中取出数据,直到有匹配的左括号
    3. 然后计算 '1+2' 将结果 3 入栈
    4. 遇到 ')' ,计算 '6/3' 将结果 2.0 入栈
    5. 最再计算表达式 2*2.0 得出最终结果: 4.0

    SimpleCalculator 不支持小数,改写 get_result 函数:

        def get_result(self):
            decimal = 0
            has_dot = False
            factor = 0
            for x in self.expression:
                v = x.strip()
                if not v:
                    continue
                
                if v == '.':
                    has_dot = True
                    factor = 0.1
                elif v in self._priority:
                    self.number_stack.push(decimal)
                    decimal = 0
                    has_dot = False
                    factor = 0
                    self.cmp_and_calc(v)
                    self.symbol_stack.push(v)
                elif v in self._digits:
                    if not has_dot:
                        decimal = decimal * 10 + self._digits[v]
                    else:
                        decimal = decimal + self._digits[v] * factor
                        factor = factor * 0.1
                else:
                    raise UnsupportExpressionError(f'unsupport operation: "{v}" in expression: {self.expression}')
    
            self.number_stack.push(decimal)
            operation = self.symbol_stack.pop()
            while operation:
                ret = self._calc_helper(operation)
                self.number_stack.push(ret)
                operation = self.symbol_stack.pop()
            ret = self.number_stack.pop()
    
            return ret
    

    带括号的表达式求解:

    class BracketsCalculator:
        _match_pair = {
            ')': '(',
            ']': '[',
            '}': '{',
        }
        def __init__(self, expression):
            self.exp_stack = Stack()
            self.expression = expression
            self._result = self.get_result()
    
        @property
        def result(self):
            return self._result
    
        def get_result(self):
            exp = ''
            for x in self.expression:
                v = x.strip()
                if not v:
                    continue
    
                if v in (')', ']', '}'):
                    val = self.exp_stack.pop()
                    while val != self._match_pair[v]:
                        exp = f'{val}{exp}'
                        val = self.exp_stack.pop()
                    
                    ret = SimpleCalculator(exp).result
                    self.exp_stack.push(ret)
                    exp = ''
                else:
                    self.exp_stack.push(v)
            
            val = self.exp_stack.pop()
            while val is not None:
                exp = f'{val}{exp}'
                val = self.exp_stack.pop()
            
            return SimpleCalculator(exp).result
    
  • 相关阅读:
    递归和this指向
    作用域,闭包
    三种存储方式
    事件流,冒泡,捕获,事件委托
    centos添加登陆成功提示消息
    centos7下安装oracle11g R2报错
    linux下从home分区扩展到根分区
    linux下搭建mongodb副本集
    linux服务下使用nginx之后数据导出超时
    linux下搭建git服务器
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/12238099.html
Copyright © 2020-2023  润新知