使用 Python 实现一个简单的栈(Stack)类(长文讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 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 从零实现一个功能完善的栈类,并理解其在实际场景中的应用。以下是关键知识点的总结:
- 核心操作:压栈、弹栈、查看栈顶、判断空栈。
- 异常处理:通过
try-except
或直接抛出错误确保代码健壮性。 - 扩展性设计:通过继承或参数化实现容量限制、类型检查等高级功能。
进阶方向
- 学习其他数据结构(队列、链表、树)的实现。
- 探索栈在算法中的应用(如深度优先搜索、表达式求值)。
- 研究 Python 内置的
collections.deque
或第三方库(如pythonds
)对栈的优化实现。
掌握基础数据结构的实现原理,是通向高级编程与算法优化的必经之路。希望本文能为你的编程学习之路提供一份清晰的指南!