栈实现简单四则运算

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

栈主要包含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
上一篇:System : Floating Point Operation


下一篇:Error disabling address space randomization: Operation not permitted