您的位置:首页 > 编程语言 > Python开发

python算法——字符串表达式的计算(转自:无限大地NLP_空木)

2017-08-20 14:42 507 查看
原文戳这里!!!

preface:最近有个面试,被要求给出一个字符串表达式,计算出结果。本以为是见到过的,想着用一个栈,然后被面试官打断说你这样是有问题的,然后想了说用树,又被打断说是有问题的,再仔细想想。结果还是没整出来。哎。回来翻了下leetcode发现有两道类似。

leetcode 224 Basic Calculator https://leetcode.com/problems/basic-calculator/有点类似,可这特么只用加减和括号不用乘除啊,妈的智障。这题用栈AC了。
leetcode 227 Basic Calculator II https://leetcode.com/problems/basic-calculator-ii/也有点类似,只是差了括号。

但这两道还是不够。翻书加上与同仁的讨论,发现只需要将表达式化为二叉树的后缀表达式即可,有了后缀表达式,就比较简单了。后缀表达式是能够唯一确定表达式树的。后序遍历表达式树即可。用栈对后缀表达式进行处理也可以的。主要还是需要将字符串表达式化为后缀表达式。

另外,计算字符串表达式,Python有个内置函数eval(),直接使用eval("1+2*(3-1)-4")即可。

coding:

[python] view
plain copy

# -*- coding: utf-8 -*-  

""" 

Created on Sun Jul 10 15:39:28 2016 

 

@author: Administrator 

"""  

operator_precedence = {  

    '(' : 0,  

    ')' : 0,  

    '+' : 1,  

    '-' : 1,  

    '*' : 2,  

    '/' : 2  

}  

  

def postfix_convert(exp):  

    ''''' 

    将表达式字符串,转为后缀表达式 

    如exp = "1+2*(3-1)-4" 

    转换为:postfix = ['1', '2', '3', '1', '-', '*', '+', '4', '-'] 

    '''  

    stack = []          #运算符栈,存放运算符  

    postfix = []        #后缀表达式栈  

    for char in exp:  

#        print char, stack, postfix  

        if char not in operator_precedence:#非符号,直接进栈  

            postfix.append(char)  

        else:  

            if len(stack) == 0:#若是运算符栈啥也没有,直接将运算符进栈  

                stack.append(char)  

            else:  

                if char == "(":  

                    stack.append(char)             

                elif char == ")":#遇到了右括号,运算符出栈到postfix中,并且将左括号出栈  

                    while stack[-1]!="(":  

                        postfix.append(stack.pop())  

                    stack.pop()  

                      

                elif operator_precedence[char] > operator_precedence[stack[-1]]:  

                    #只要优先级数字大,那么就继续追加  

                    stack.append(char)  

                else:  

                    while len(stack)!=0:  

                        if stack[-1]=="(":#运算符栈一直出栈,直到遇到了左括号或者长度为0  

                            break  

                        postfix.append(stack.pop())#将运算符栈的运算符,依次出栈放到表达式栈里面  

                    stack.append(char)#并且将当前符号追放到符号栈里面  

                      

    while len(stack)!=0:#如果符号站里面还有元素,就直接将其出栈到表达式栈里面  

        postfix.append(stack.pop())  

    return postfix  

#===========================这部分用于构造表达式树,不涉及计算================================#  

class Node(object):  

    def __init__(self, val):  

        self.val = val  

        self.left = None  

        self.right = None  

def create_expression_tree(postfix):  

    """ 

    利用后缀表达式,构造二叉树 

    """  

    stack = []  

    #print postfix  

    for char in postfix:  

        if char not in operator_precedence:  

            #非操作符,即叶子节点  

            node = Node(char)     

            stack.append(node)  

        else:  

            #遇到了运算符,出两个,进一个。  

            node = Node(char)  

            right = stack.pop()  

            left = stack.pop()  

            node.right = right  

            node.left = left  

            stack.append(node)  

    #将最后一个出了即可。  

    return stack.pop()  

def inorder(tree):  

    if tree:  

        inorder(tree.left)  

        print tree.val  

        inorder(tree.right)  

#=============================这部分用于计算值===================================#  

def calculate(num1, op, num2):  

    if not num1.isdigit() and not num2.isdigit():  

        raise "num error"  

    else:  

        num1 = int(num1)  

        num2 = int(num2)  

    if op == "+":  

        return num1 + num2  

    elif op == "-":  

        return num1 - num2  

    elif op == "*":  

        return num1 * num2  

    elif op == "/":  

        if num2==0:  

            raise "zeros error"  

        else:  

            return num1/num2  

    else:  

        raise "op error"  

      

def cal_expression_tree(postfix):  

    stack = []  

    for char in postfix:  

        stack.append(char)  

        if char in "+-*/":  

            op    = stack.pop()  

            num2  = stack.pop()  

            num1  = stack.pop()  

            value = calculate(num1, op, num2)  

            value = str(value)#计算结果是数值类型,将其化为字符串类型  

            stack.append(value)  

    return int(stack[0])  

if __name__=="__main__":  

    #另外异常情况的判断的话,可以使用try catch  

    exp = "1+2*(3-1)-4"  

    postfix = postfix_convert(exp)  

      

    #print "postfix:",postfix  

    #tree    = create_expression_tree(postfix)  

    #inorder(tree)  

      

    print cal_expression_tree(postfix)  

首先,运算符的优先级的定义operator_precedence字典的定义比较重要。遇到了(3-1*2)与(3*1-1)这两种情况,对三种运算符的优先级左右括号、减号、乘号,就不能简单的出栈进栈进行运算了。

其次,postfix_convert()函数将字符串表达式化为后缀表达式是关键。

最后,对于异常情况的处理,可以使用try catch,或者提前判断,这里在calculate()函数里面做了些判断。

主要参考:

Expression tree
《数据结构与高分笔记》P132
顺序堆栈应用--表达式计算

转载请认证:无限大地nlp_空木的博客
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息