前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀

前缀表达式的计算机求值

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第1张图片

注意:在前缀表达式中,遇到运算符时,如“-”,是栈顶元素 - 次顶元素

中缀表达式

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第2张图片

后缀表达式

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第3张图片

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第4张图片 注意:在后缀表达式中,遇到运算符时,如“-”,是次顶元素 - 栈顶元素

逆波兰计算器

思路如后缀表达式中的第二张图所示

代码实现如下:

# 用数组模拟栈
class ArrayStack:
    def __init__(self, size):
        self.max_size = size  # 栈的最大容量
        self.top = -1  # top 表示栈顶
        self.stack = []  # 用列表表示数组

    # 判断栈满
    def is_full(self):
        return self.top == self.max_size - 1

    # 判断栈空
    def is_empty(self):
        return self.top == -1

    # 入栈
    def push(self, ele):
        if self.is_full():
            print("栈已满")
        else:
            self.top += 1
            self.stack.insert(self.top, ele)

    # 出栈
    def pop(self):
        if self.is_empty():
            print("栈空")
        else:
            val = self.stack.pop(self.top)
            self.top -= 1
            return val


# 实现逆波兰表达式
def poland(expression: str):
    # 以空格分割输入的逆波兰表达式
    str_list = expression.split(" ")

    # 创建操作数栈
    num_stack = ArrayStack(len(str_list))

    operator = {
        "+": lambda x, y: x + y,
        "-": lambda x, y: x - y,
        "*": lambda x, y: x * y,
        "/": lambda x, y: x / y
    }
    # 从左往右遍历逆波兰式列表
    for i in str_list:
        try:
            i = float(i)
            # 遇到数字将其压入操作数栈
            num_stack.push(float(i))
        except Exception:  # 遇到运算符弹出两个操作数进行运算,并将结果压入数栈
            # 弹出两个操作数,注意是 次顶元素 运算符(如 -) 栈顶元素
            num2 = num_stack.pop()
            num1 = num_stack.pop()
            res = operator[i](num1, num2)
            if res:
                # 将运算结果压入栈
                num_stack.push(res)
            else:
                raise ValueError("不支持运算符{}".format(i))

    print("运算结果为:", num_stack.pop())


poland("3 4 + 5 * 6 -")
poland("4 5 * 8 - 60 + 8 2 / +")

中缀表达式转后缀表达式

思路分析

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第5张图片

示意图

例子:将中缀表达式:1+((2+3)* 4)-5  转为后缀表达式: 1 2 3 + 4 * + 5 - 

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第6张图片

前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第7张图片前缀(波兰式)、中缀、后缀(逆波兰)表达式;中缀转后缀_第8张图片

代码实现 

# 用数组模拟栈
class ArrayStack:
    def __init__(self, size):
        self.max_size = size  # 栈的最大容量
        self.top = -1  # top 表示栈顶
        self.stack = []  # 用列表表示数组

    # 判断栈满
    def is_full(self):
        return self.top == self.max_size - 1

    # 判断栈空
    def is_empty(self):
        return self.top == -1

    # 入栈
    def push(self, ele):
        if self.is_full():
            print("栈已满")
        else:
            self.top += 1
            self.stack.insert(self.top, ele)

    # 出栈
    def pop(self):
        if self.is_empty():
            print("栈空")
        else:
            val = self.stack.pop(self.top)
            self.top -= 1
            return val

    # 查看栈顶元素
    def get_top(self):
        if self.is_empty():
            print("栈空")
        else:
            return self.stack[self.top]


# 中缀表达式转后缀表达式
class InfixToPostfix:
    def __init__(self, size):
        # 1、初始化两个栈 s1, s2
        self.s1 = ArrayStack(size)
        self.s2 = ArrayStack(size)

    def is_high_priority(self, oper1, oper2):
        """判断 oper1 的优先级是否大于 oper2,是返回 True"""
        priority_dict = {
            '+': 0,
            '-': 0,
            '*': 1,
            '/': 1
        }

        prio1 = priority_dict.get(oper1)
        prio2 = priority_dict.get(oper2)
        if prio1 is None:
            raise ValueError('不支持运算符' + oper1)
        if prio2 is None:
            raise ValueError('不支持运算符' + oper2)

        return prio1 > prio2

    def infix2postfix(self, infix_exp: str) -> list:
        """将中缀表达式转为后缀表达式返回"""
        # 将中缀表达式字符串转换为列表
        infix_list = self.str_to_list(infix_exp)

        # 2、从左往右遍历中缀表达式,即遍历列表的每一个元素 ele
        for ele in infix_list:
            # 3、遇到的元素 ele 是数字,直接压入栈 s2
            if '0' <= ele <= '9':
                self.s2.push(ele)
            # 4、遇到的元素 ele 是运算符,按以下三种情况处理:
            elif ele != '(' and ele != ')':
                while True:
                    # 4.1、如果栈 s1 为空,或者 s1 栈顶为左括号 ( ,则直接将元素 ele 压入栈 s1
                    if self.s1.is_empty() or self.s1.get_top() == '(':
                        self.s1.push(ele)
                        break
                    # 4.2、如果不满足4.1,则比较元素 ele 和 s1 栈顶元素的优先级,
                    #       如果 ele 优先级大于 s1 栈顶元素,则直接将元素 ele 压入栈 s1
                    elif self.is_high_priority(ele, self.s1.get_top()):
                        self.s1.push(ele)
                        break
                    # 4.3、如果不满足4.1、4.2,则弹出 s1 栈顶元素压入 s2,
                    #       然后回到 4.1 步重新判断元素 ele 和 s1 栈顶元素的关系
                    else:
                        self.s2.push(self.s1.pop())
            # 5、遇到的元素 ele 是左括号 ( ,直接压入栈 s1
            elif ele == '(':
                self.s1.push(ele)
            # 6、遇到的元素 ele 是右括号 ) ,依次弹出 s1 元素,并将弹出的元素压入 s2,
            #       直到弹出的元素是 左括号 ( ,则停止弹出 s1 元素,并且将弹出的左括号丢弃,不压入栈 s2
            else:
                val = self.s1.pop()
                while val != '(':
                    self.s2.push(val)
                    val = self.s1.pop()

        # 7、重复步骤2-6,直到列表遍历完毕,将栈 s1 剩余的元素依次弹出压入栈 s2 ,
        #       此时栈 s2 中的元素,从栈底到栈顶的顺序就是得到的后缀表达式
        while not self.s1.is_empty():
            self.s2.push(self.s1.pop())
        result = []
        # 依次弹出 s2 栈顶元素,并添加到列表 result 中
        while not self.s2.is_empty():
            result.append(self.s2.pop())
        # 将列表 result 反转,得到的才是后缀表达式
        result.reverse()
        return result

    def str_to_list(self, infix_expression: str) -> list:
        """将中缀表达式字符串转换为列表"""
        # 将字符串转换为列表,并去除字符串中的空格
        infix_list = [i for i in infix_expression if i != ' ']

        # 遍历列表,将多位数合并成一个字符串
        i = 0
        while i < len(infix_list):
            val = infix_list[i]
            # 如果该元素是数字
            if '0' <= val <= '9':
                next = infix_list[i + 1] if i + 1 < len(infix_list) else None
                # 判断列表的下一个元素是不是数字,是的话说明是多位数,需要进行拼接
                while next and '0' <= next <= '9':
                    val += next  # 拼接数字
                    infix_list.pop(i + 1)  # 并从列表中移除下一位数字
                    # 继续判断下一个元素是不是数字,如果是还需要继续拼接
                    next = infix_list[i + 1] if i + 1 < len(infix_list) else None
                # 将拼接好的多位数赋值给i,即列表中遇到的多位数的第一个数字的位置
                infix_list[i] = val
            i += 1

        return infix_list  # 返回转换后的中缀表达式列表


# 1+((2+3)* 4)-5 转为后缀表达式: 1 2 3 + 4 * + 5 -
s = '1+((2+3)* 4)-5'
infix_to_postfix = InfixToPostfix(len(s))
print(infix_to_postfix.infix2postfix(s))  # 1 2 3 + 4 * + 5 -

你可能感兴趣的:(数据结构和算法,python,后端,数据结构)