栈的运用 | 青训营 X 豆包MarsCode AI 刷题

82 阅读4分钟

栈(Stack)是一种先进后出(LIFO, Last In First Out)的数据结构,意味着最后插入的元素会最先被移除。栈广泛应用于算法设计、程序执行、解析表达式、回溯算法等多个场景。由于其简单的操作特性,栈在许多情况下都被用作临时数据存储和处理结构。

一、栈的基本操作

栈主要支持以下基本操作:

  1. 压栈(Push):将一个元素添加到栈顶。
  2. 弹栈(Pop):移除并返回栈顶元素。
  3. 查看栈顶元素(Peek/Top):返回栈顶元素但不移除它。
  4. 判断栈是否为空(isEmpty):检查栈中是否还有元素。
  5. 获取栈的大小(size):返回栈中元素的个数。

二、栈的实现

栈可以通过数组或链表来实现。以下是使用 Python 列表实现的一个栈类。

class Stack:
    def __init__(self):
        self.items = []  # 使用列表来存储栈中的元素

    def is_empty(self):
        """判断栈是否为空"""
        return len(self.items) == 0

    def push(self, item):
        """压栈,添加元素到栈顶"""
        self.items.append(item)

    def pop(self):
        """弹栈,移除并返回栈顶元素"""
        if self.is_empty():
            raise IndexError("pop from empty stack")
        return self.items.pop()

    def peek(self):
        """查看栈顶元素"""
        if self.is_empty():
            raise IndexError("peek from empty stack")
        return self.items[-1]

    def size(self):
        """获取栈的大小"""
        return len(self.items)

    def display(self):
        """显示栈中的元素"""
        print("Stack:", self.items)


# 使用示例
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
stack.display()  # 输出: Stack: [1, 2, 3]

print("栈顶元素:", stack.peek())  # 输出: 栈顶元素: 3
print("弹出元素:", stack.pop())    # 输出: 弹出元素: 3
stack.display()  # 输出: Stack: [1, 2]
print("栈大小:", stack.size())     # 输出: 栈大小: 2

三、栈的应用场景

栈在计算机科学中有许多应用,下面介绍几种常见的应用场景:

  1. 表达式求值和解析: 栈常用于转换和求值数学表达式。例如,在中缀表达式转后缀表达式(逆波兰表示法)时,使用栈来暂存运算符和括号。

    def precedence(op):
        """定义运算符的优先级"""
        if op == '+' or op == '-':
            return 1
        if op == '*' or op == '/':
            return 2
        return 0
    
    def infix_to_postfix(expression):
        """中缀表达式转后缀表达式"""
        output = []
        stack = Stack()
        for char in expression:
            if char.isalnum():  # 如果是操作数,直接添加到输出
                output.append(char)
            elif char == '(':
                stack.push(char)
            elif char == ')':
                while not stack.is_empty() and stack.peek() != '(':
                    output.append(stack.pop())
                stack.pop()  # 弹出左括号
            else:  # 运算符
                while (not stack.is_empty() and
                       precedence(stack.peek()) >= precedence(char)):
                    output.append(stack.pop())
                stack.push(char)
        while not stack.is_empty():
            output.append(stack.pop())
        return ''.join(output)
    
    # 使用示例
    expression = "A+B*(C^D-E)"
    postfix = infix_to_postfix(expression)
    print("后缀表达式:", postfix)  # 输出: 后缀表达式: ABDC^E-*+
    
  2. 回溯算法: 回溯算法(Backtracking)通常使用栈来存储状态。例如,在解决迷宫问题、八皇后问题等时,可以使用栈来存储当前路径和状态。

    def solve_maze(maze, start, end):
        stack = Stack()
        stack.push(start)
        visited = set()
        while not stack.is_empty():
            current = stack.pop()
            if current == end:
                return True
            visited.add(current)
            x, y = current
            # 四个方向
            for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                next_cell = (x + dx, y + dy)
                if (0 <= next_cell[0] < len(maze) and
                    0 <= next_cell[1] < len(maze[0]) and
                    maze[next_cell[0]][next_cell[1]] == 0 and
                    next_cell not in visited):
                    stack.push(next_cell)
        return False
    
    # 使用示例
    maze = [
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 0],
        [0, 1, 0, 0],
    ]
    start = (0, 0)
    end = (3, 3)
    print("找到路径:", solve_maze(maze, start, end))  # 输出: 找到路径: True
    
  3. 函数调用管理: 在程序执行过程中,函数调用的上下文会被存储在栈中。每当调用一个函数时,当前状态会被压入栈中,在函数返回时,从栈中弹出状态,使得程序能够恢复到调用之前的状态。

  4. 浏览器的历史记录: 浏览器的前进和后退功能可以使用两个栈来实现,分别用于存储历史浏览记录和前进记录。

四、总结

栈是一种简单但功能强大的数据结构,其先进后出的特性使其在许多程序和算法中得到广泛应用。通过栈的基本操作(压栈、弹栈、查看栈顶元素等),我们可以高效地管理数据并解决问题。无论是在表达式求值、回溯算法,还是在管理函数调用等场景中,栈都扮演着重要角色。

掌握栈的使用和实现,将为我们在算法设计和编程实践中提供强有力的工具,帮助我们更高效地解决各种问题。