使用 Python 实现一个简单的栈(Stack)类(长文讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

在编程世界中,数据结构是构建高效算法和复杂系统的基石。栈(Stack)作为最基础且应用广泛的线性数据结构之一,其核心特性“后进先出(LIFO)”在解决实际问题时展现出强大的灵活性。无论是浏览器的回退功能、括号匹配验证,还是表达式求值,栈的身影无处不在。本文将从零开始,逐步讲解如何使用 Python 实现一个简单但功能完整的栈类。通过代码示例与实际案例的结合,帮助读者理解其底层逻辑,并掌握如何将理论转化为可复用的代码模块。


栈(Stack)的基本概念与特性

什么是栈?

栈是一种遵循 后进先出(LIFO, Last In First Out) 原则的数据结构。想象一个叠放整齐的盘子塔:当你需要取用盘子时,只能从顶部取出最晚放置的那个,而底部的盘子必须等到上方所有盘子都被取走后才能被使用。这一特性完美体现了栈的核心操作逻辑。

栈的核心操作

栈的主要操作包括:

  • 压栈(Push):将一个元素添加到栈顶。
  • 弹栈(Pop):移除并返回栈顶的元素。
  • 查看栈顶(Peek):返回栈顶元素但不移除。
  • 判断栈是否为空(IsEmpty):返回布尔值表示栈的状态。

栈的常见应用场景

  • 括号匹配验证:检查代码或数学表达式中的括号是否正确闭合。
  • 浏览器历史记录管理:实现“前进”和“后退”功能。
  • 递归算法的底层实现:函数调用栈(Call Stack)即为栈结构的典型应用。

从零开始实现栈类:代码分步解析

第一步:定义栈类的基本结构

在 Python 中,可以通过一个空列表(List)模拟栈的存储行为。列表的 append() 方法可实现“压栈”,而 pop() 方法可实现“弹栈”。基于此,我们可以定义一个基础栈类:

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

第二步:实现核心方法

1. 压栈方法(Push)

def push(self, item):
    """将元素添加到栈顶"""
    self.items.append(item)
  • 比喻:就像将盘子叠放到塔顶,append() 操作会自动将元素添加到列表末尾,即栈的顶部。

2. 弹栈方法(Pop)

def pop(self):
    """移除并返回栈顶元素"""
    if not self.is_empty():
        return self.items.pop()
    else:
        raise IndexError("弹栈失败:栈为空!")
  • 异常处理:当尝试从空栈弹出元素时,抛出 IndexError,避免程序崩溃。

3. 查看栈顶元素(Peek)

def peek(self):
    """返回栈顶元素但不移除"""
    if not self.is_empty():
        return self.items[-1]
    else:
        raise IndexError("栈为空,无法查看栈顶!")
  • 列表索引技巧:通过 items[-1] 直接访问列表最后一个元素,即栈顶。

4. 判断栈是否为空(IsEmpty)

def is_empty(self):
    """返回栈是否为空的布尔值"""
    return len(self.items) == 0

第三步:扩展方法与实用功能

5. 获取栈的大小(Size)

def size(self):
    """返回栈内元素数量"""
    return len(self.items)

完整代码与测试

整合上述方法后,完整的栈类代码如下:

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.is_empty():
            return self.items.pop()
        else:
            raise IndexError("弹栈失败:栈为空!")

    def peek(self):
        if not self.is_empty():
            return self.items[-1]
        else:
            raise IndexError("栈为空,无法查看栈顶!")

    def is_empty(self):
        return len(self.items) == 0

    def size(self):
        return len(self.items)

测试代码示例

my_stack = Stack()

my_stack.push("苹果")
my_stack.push("香蕉")
my_stack.push("橙子")

print("当前栈顶元素:", my_stack.peek())  # 输出:"橙子"
print("栈的大小:", my_stack.size())      # 输出:3

print("弹出的元素:", my_stack.pop())     # 输出:"橙子"
print("弹出后栈顶元素:", my_stack.peek()) # 输出:"香蕉"

print("是否为空?", my_stack.is_empty())  # 输出:False

扩展功能:增强栈类的实用性

1. 添加最大容量限制

通过在初始化时设置 max_size 参数,可限制栈的容量:

class BoundedStack(Stack):  # 继承基础栈类
    def __init__(self, max_size):
        super().__init__()
        self.max_size = max_size

    def push(self, item):
        if self.size() < self.max_size:
            super().push(item)
        else:
            raise OverflowError(f"栈已满(最大容量:{self.max_size})!")

2. 类型安全栈

确保栈只能存储特定类型的元素(例如整数):

class TypedStack(Stack):
    def __init__(self, data_type):
        super().__init__()
        self.data_type = data_type

    def push(self, item):
        if isinstance(item, self.data_type):
            super().push(item)
        else:
            raise TypeError(f"仅允许类型:{self.data_type.__name__}")

实际案例:使用栈验证括号匹配

问题描述

给定一个字符串,判断其中的括号是否正确闭合。例如:

  • "()[]{}" → 正确
  • "([)]" → 错误

解决方案

利用栈的 LIFO 特性,遍历字符串时:

  • 遇到左括号(([{)时压栈。
  • 遇到右括号时,弹栈并检查是否匹配。
def is_valid(s):
    stack = Stack()
    pairs = {")": "(", "]": "[", "}": "{"}
    
    for char in s:
        if char in pairs.values():
            stack.push(char)
        elif char in pairs.keys():
            if stack.is_empty() or stack.pop() != pairs[char]:
                return False
        else:
            # 忽略非括号字符(可选)
            continue
    return stack.is_empty()

print(is_valid("()[]{}"))  # 输出:True
print(is_valid("([)]"))    # 输出:False

总结与进阶建议

通过本文的讲解,读者应能掌握如何使用 Python 从零实现一个功能完善的栈类,并理解其在实际场景中的应用。以下是关键知识点的总结:

  1. 核心操作:压栈、弹栈、查看栈顶、判断空栈。
  2. 异常处理:通过 try-except 或直接抛出错误确保代码健壮性。
  3. 扩展性设计:通过继承或参数化实现容量限制、类型检查等高级功能。

进阶方向

  • 学习其他数据结构(队列、链表、树)的实现。
  • 探索栈在算法中的应用(如深度优先搜索、表达式求值)。
  • 研究 Python 内置的 collections.deque 或第三方库(如 pythonds)对栈的优化实现。

掌握基础数据结构的实现原理,是通向高级编程与算法优化的必经之路。希望本文能为你的编程学习之路提供一份清晰的指南!

最新发布