中缀表示形式的整数简单算术表达式求值 python实现

中缀表示形式的整数简单算术表达式求值

1. 题目

设有一个算术表达式为:a+b*(c-d)+b/d,其中a,b,c,d均为整数,且d不为0,请完成表达式求值运算,并把计算结果输出屏幕。

2. 算法思想

该解法一个分为三个部分,它们分别是:创建一个栈类,创建一个可将中缀表达式转换为后缀表达式的函数和创建一个可以对后缀表达式进行求值的函数。

其具体步骤为:

2.1 建立一个栈类,可以用于实例化一个空栈,类中也有5个方法,分别是:判断栈是否为空,加入元素,弹出元素,返回栈顶元素和返回栈的大小

2.2 定义一个可判别操作码优先级的函数,其中“(”的优先级最小,为1;“+”与“-”优先级为2;“*”和“/”优先级为3;“)”优先级为4.

2.3 创建一个可将中缀表达式转换为后缀表达式的函数,首先创建一个空栈,并对输入的字符串形式的表达式进行字符遍历,对于每个元素的操作情况如下:

a. 若元素为运算数,则直接输出。

b. 若栈为空,且该元素为操作码,其不为左右括号,则可以将元素直接压入栈中。

c. 如果操作码为左括号,直接压入栈。

d. 如果操作码为右括号,将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)

e. 对于非括号类的操作码:

若优先级大于栈顶运算符时,将它压栈。

若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到运算符大于栈顶运算符优先级为止,然后将该运算符压栈。

f. 当各元素处理完毕,则把栈中存留的运算符一并输出。

g. 由于左括号不应输出,那么将后缀表达式中的左括号去除。

2.4 创建一个可以对后缀表达式进行求值的函数,同理,首先创建一个空栈,并对输入的字符串形式的表达式进行字符遍历,对于每个元素的操作情况如下:

a. 当元素为数字时,压栈。

b. 当元素为操作码时,先将栈中的前两个元素(注意这两个操作数的运算顺序!)弹出,并作对应的运算,将一次运算得出的结果送入栈中。

c. 在栈中的最后一个元素即为最终运算结果

2.5 设置主函数,对函数输入,并检测输出

3. 具体实现

3.1 创建一个栈类

class Stack(object):
    """栈的实现"""
    def __init__(self):
         self.items = []
 
    def is_empty(self):
        """判断是否为空"""
        return self.items == []
 
    def push(self, item):
        """加入元素"""
        self.items.append(item)
 
    def pop(self):
        """弹出元素"""
        return self.items.pop()
 
    def peek(self):
        """返回栈顶元素"""
        return self.items[-1]
 
    def size(self):
        """返回栈的大小"""
        return len(self.items)

3.2 定义一个可判别操作码优先级的函数

def priority(op):
    """定义一个可判别操作码优先级的函数"""
    global temp
    if op == '(':
        temp = 1
    elif op == '+':
        temp = 2
    elif op == '-':
        temp = 2
    elif op == '*':
        temp = 3
    elif op == '/':
        temp = 3
    elif op == ')':
        temp = 4
    return temp

3.3 创建一个可将中缀表达式转换为后缀表达式的函数

def infix_to_postfix(expr):
    """将中缀表达式转换为后缀表达式"""
    new_expr = ''
    #创建一个空栈
    st = Stack()
    for ele in expr:
        #若元素为运算数,则直接输出
        if ele.isdigit():
            new_expr+=ele
        #若栈为空,且该操作码不为左右括号,则可以将元素直接压入栈中
        elif st.is_empty() and ele != "(" and ele != ')':
            st.push(ele)
        else:
            #如果操作码为左括号,直接压入栈
            if ele == "(":
                st.push(ele)
            #如果操作码为右括号,将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
            elif ele == ")":
                while True:
                    if st.is_empty():
                        break
                    elif st.peek() != "(":
                        new_expr+=st.pop()
                    elif st.peek() == "(":
                        st.pop()
            else:
                """对于运算符:
                若优先级大于栈顶运算符时,将它压栈。
                若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;
                再比较新的栈顶运算符,直到运算符大于栈顶运算符优先级为止,
                然后将该运算符压栈
                """
                prior = priority(ele)
                peek = st.peek()
                peek_prior = priority(peek)
                if prior > peek_prior:
                    st.push(ele)
                else:
                    new_expr+=st.pop()
                    while True:
                        if st.is_empty():
                            break
                        elif prior<=priority(st.peek()):
                            new_expr+=st.pop()
                        else:
                            break
                    st.push(ele)
    #当各元素处理完毕,则把栈中存留的运算符一并输出
    while True:
        if not st.is_empty():
            new_expr+=st.pop()
        else:
            break
    #由于左括号不应输出,那么将后缀表达式中的左括号去除
    return new_expr.replace("(","")

3.4 创建一个可以对后缀表达式进行求值的函数

def cal_post(post):
    """利用后缀表达式求值"""
    #先创建一个空栈
    st = Stack()
    #对后缀表达式各个字符进行遍历
    for ele in post:
        #当元素为数字时,压栈
        if ele.isdigit():
            st.push(ele)
        else:
            #当元素为操作码时,先将栈中的前两个元素弹出,并作对应的运算
            right = int(st.pop())
            left = int(st.pop())
            if ele == "+":
                res = left + right
            elif ele == '-':
                res = left - right
            elif ele == '*':
                res = left * right
            elif ele == '/':
                res = left / right
            #将一次运算得出的结果送入栈中
            st.push(res)
    #在栈中的最后一个元素即为最终运算结果
    return st.pop()

3.5 设置主函数

def main():
    expression = input("请输入一个合法的表达式:")
    res = cal_post(infix_to_postfix(expression))
    print("运算结果为:"+str(res))

4. 实测结果

输入

main()
请输入一个合法的表达式:1+2*(7-4)+9/3

输出

运算结果为:10

本人第一次写博客,请各位大佬批评指点!

算法分析: 1. 初始化一个空s用于存储操作数和操作符; 2. 从左到右扫描中缀表达式; 3. 如果是数字,则将其压入中; 4. 如果是操作符,分两种情况: a. 如果操作符是左括号 “(”,则直接将其压入中; b. 如果操作符是其他符号,则需要进行操作,具体操作分以下几种情况: 判断顶元素的优先级是否大于等于当前操作符的优先级,如果是,则进行以下操作: (1) 弹出两个操作数并弹出操作符; (2) 对两个操作数进行计算,并将结果压入中; (3) 重复步骤4,直到顶元素优先级小于当前操作符。 将当前操作符压入中; c. 如果操作符是右括号“)”,则需要进行以下操作: (1) 重复步骤4直到遇到左括号“(”为止; (2) 弹出左括号“(”; 5. 将表达式中的所有操作数和操作符全部扫描完后,如果中还有元素,则依次弹出进行计算,最后顶元素即为表达式的值。 Python代码实现: ```python def infix_to_postfix(expression): # 优先级字典 priority = {'+': 1, '-': 1, '*': 2, '/': 2, '(': 0, ')': 0} # 初始化 stack = [] # 初始化后缀表达式 postfix = '' # 遍历中缀表达式 for item in expression: # 如果是数字,直接加入后缀表达式 if item.isdigit(): postfix += item # 如果是操作符 else: # 左括号直接入 if item == '(': stack.append(item) # 右括号则依次弹出中的元素,直到弹出左括号 elif item == ')': while stack[-1] != '(': postfix += stack.pop() stack.pop() # 如果是其他操作符,则需判断顶元素的优先级 else: # 如果为空或顶元素为左括号,则直接入 if not stack or priority[item] > priority[stack[-1]]: stack.append(item) # 弹出中元素,并将它们加入后缀表达式 else: while stack and priority[item] <= priority[stack[-1]]: postfix += stack.pop() stack.append(item) # 将中剩余元素弹出,并加入后缀表达式 while stack: postfix += stack.pop() return postfix def postfix_eval(postfix): # 初始化 stack = [] # 遍历后缀表达式 for item in postfix: # 如果是数字,则将其转换成整数并压入中 if item.isdigit(): stack.append(int(item)) # 如果是操作符,则弹出顶元素进行运算,并将结果压入中 else: operand2 = stack.pop() operand1 = stack.pop() if item == '+': stack.append(operand1 + operand2) elif item == '-': stack.append(operand1 - operand2) elif item == '*': stack.append(operand1 * operand2) elif item == '/': stack.append(operand1 / operand2) # 返回顶元素,即为表达式的值 return stack.pop() # 测试 expression = '1+((2+3)*4)-5' postfix = infix_to_postfix(expression) value = postfix_eval(postfix) print(value) # 输出:16 ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sentar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值