当前位置: 首页 > news >正文

【数据结构与算法学习笔记】栈

前言

本文为个人学习的算法学习笔记,学习笔记,学习笔记不是经验分享与教学,不是经验分享与教学,不是经验分享与教学,若有错误各位大佬轻喷(T^T)。主要使用编程语言为Python3,各类资料题目源于网络,主要自学途径为博学谷,侵权即删。

一、栈的基本定义与核心特性

1. 定义

栈是一种线性数据结构,其核心规则为只允许在栈的一端进行数据的入栈(push)和出栈(pop)操作—— 该操作端称为 “栈顶(Top)”,另一端固定为 “栈底(Bottom)”,栈底元素无法直接操作。

2. 核心特性:后进先出(LIFO)

“后进先出” 是栈的标志性特点,即最后进入栈的元素,会最先被弹出栈。例如:先入栈元素 A,再入栈元素 B,出栈时会先弹出 B,再弹出 A。生活类比:叠放的杯子,新杯子只能放在最顶端(栈顶),取杯子时也只能从顶端拿取,最底层(栈底)的杯子需等上方所有杯子移除后才能接触。

3. 核心操作与时间复杂度

栈的核心操作仅围绕栈顶展开,共 2 类基础操作,且入栈、出栈的时间复杂度均为 O (1)(无需遍历数据,直接操作栈顶,效率极高):

  • 入栈(push):将新元素添加到栈顶,栈的元素个数 + 1;
  • 出栈(pop):将栈顶元素从栈中移除,栈的元素个数 - 1,并返回被移除的元素;
  • 延伸操作(常用):查看栈顶元素(peek):仅返回栈顶元素的值,不修改栈结构。

二、栈的两种 Python 实现方式

根据文档内容,栈可通过 “数组” 或 “链表” 实现,两种方式均能满足核心操作需求,且时间复杂度保持 O (1)。

1. 数组实现(最常用)

实现原理

利用 Python 列表(List)模拟数组,通过 “栈顶指针”(变量top)跟踪栈顶位置:

  • 初始状态:top = -1(表示栈空,无任何元素);
  • 入栈:top += 1,将元素追加到列表对应索引(list[top]);
  • 出栈:取出list[top]top -= 1
  • 栈满判断:若用固定容量数组,需判断top == 容量-1(Python 列表可动态扩容,此判断可选);
  • 栈空判断:top == -1
Python 代码实现
class ArrayStack:def __init__(self, capacity: int = None):"""初始化数组栈:param capacity: 栈的固定容量(None表示动态扩容)"""self.capacity = capacity  # 固定容量(可选)self.stack = []  # 用列表模拟数组存储栈元素self.top = -1  # 栈顶指针,初始为-1(栈空)def push(self, value) -> None:"""入栈:将元素添加到栈顶"""# 若指定固定容量,判断是否栈满if self.capacity is not None and self.top == self.capacity - 1:raise Exception("栈溢出:栈已达到最大容量,无法入栈")self.top += 1self.stack.append(value)  # 列表尾部追加=栈顶入栈def pop(self):"""出栈:移除并返回栈顶元素"""if self.is_empty():raise Exception("栈下溢:栈为空,无法出栈")self.top -= 1return self.stack.pop()  # 列表尾部弹出=栈顶出栈def peek(self):"""查看栈顶元素:仅返回值,不修改栈"""if self.is_empty():raise Exception("栈为空,无栈顶元素可查看")return self.stack[self.top]def is_empty(self) -> bool:"""判断栈是否为空"""return self.top == -1def size(self) -> int:"""返回栈的元素个数"""return self.top + 1# 测试示例
if __name__ == "__main__":stack = ArrayStack(capacity=5)  # 初始化容量为5的数组栈stack.push(10)stack.push(20)stack.push(30)print("栈顶元素:", stack.peek())  # 输出:30print("出栈元素:", stack.pop())   # 输出:30print("栈是否为空:", stack.is_empty())  # 输出:Falseprint("栈元素个数:", stack.size())  # 输出:2

2. 链表实现

实现原理

通过链表节点(含data数据域和next指针域)构建栈,以 “链表头部” 作为栈顶(避免尾部操作的遍历):

  • 节点结构:每个节点存储 “元素值(data)” 和 “下一个节点的引用(next)”;
  • 栈顶:链表的第一个有效节点(虚拟头节点之后的节点);
  • 入栈:在虚拟头节点后插入新节点(新节点的next指向原栈顶);
  • 出栈:删除虚拟头节点后的第一个节点(栈顶节点),并返回其data
  • 栈空判断:虚拟头节点的nextNone
Python 代码实现
class ListNode:"""链表节点类:存储数据和下一个节点的引用"""def __init__(self, data):self.data = data  # 节点数据self.next = None  # 指向后续节点的指针(初始为None)class LinkedStack:def __init__(self):"""初始化链表栈:创建虚拟头节点(简化操作)"""self.dummy_head = ListNode(None)  # 虚拟头节点,不存储实际数据self.top = self.dummy_head  # 栈顶指针初始指向虚拟头节点self.size = 0  # 栈的元素个数(便于快速查询)def push(self, value) -> None:"""入栈:在虚拟头节点后插入新节点(栈顶)"""new_node = ListNode(value)new_node.next = self.dummy_head.next  # 新节点指向原栈顶self.dummy_head.next = new_node       # 虚拟头节点指向新栈顶self.top = new_node  # 更新栈顶指针self.size += 1def pop(self):"""出栈:删除并返回栈顶节点的 data"""if self.is_empty():raise Exception("栈下溢:栈为空,无法出栈")# 获取栈顶节点(虚拟头节点的下一个节点)top_node = self.dummy_head.nextself.dummy_head.next = top_node.next  # 虚拟头节点跳过栈顶节点(删除)# 更新栈顶指针(若栈空,指向虚拟头节点;否则指向新栈顶)self.top = self.dummy_head if self.dummy_head.next is None else self.dummy_head.nextself.size -= 1return top_node.datadef peek(self):"""查看栈顶元素:返回栈顶节点的 data"""if self.is_empty():raise Exception("栈为空,无栈顶元素可查看")return self.top.datadef is_empty(self) -> bool:"""判断栈是否为空:虚拟头节点的 next 为 None 即空"""return self.dummy_head.next is Nonedef get_size(self) -> int:"""返回栈的元素个数"""return self.size# 测试示例
if __name__ == "__main__":stack = LinkedStack()  # 初始化链表栈stack.push("A")stack.push("B")stack.push("C")print("栈顶元素:", stack.peek())  # 输出:Cprint("出栈元素:", stack.pop())   # 输出:Cprint("栈是否为空:", stack.is_empty())  # 输出:Falseprint("栈元素个数:", stack.get_size())  # 输出:2

三、栈的典型例题(Python 实现)

文档中明确提及LeetCode 20. 有效的括号是栈的经典应用场景,核心利用栈的 “后进先出” 特性解决 “匹配问题”。

1. 题目描述

给定仅包含 '('')''{''}''['']' 的字符串 s,判断字符串是否有效:

  • 左括号必须用相同类型的右括号闭合;
  • 左括号必须按正确顺序闭合(如 ([{}]) 有效,([)] 无效)。

2. 解题思路(基于栈)

  1. 建立 “左括号→右括号” 的映射表(便于快速匹配);
  2. 遍历字符串:
    • 若字符是左括号:将其对应的右括号压入栈(后续用此右括号验证匹配);
    • 若字符是右括号:
      • 栈为空(无左括号可匹配)→ 无效;
      • 弹出栈顶元素,与当前右括号不相等→ 无效;
  3. 遍历结束后,栈为空(所有左括号均匹配)→ 有效;否则→ 无效(存在未匹配的左括号)。

3. Python 代码实现

def is_valid_parentheses(s: str) -> bool:"""判断括号字符串是否有效(基于栈实现)"""# 1. 建立左括号到右括号的映射表parenthesis_map = {'(': ')', '[': ']', '{': '}'}stack = []  # 初始化空栈(用列表模拟栈)# 2. 遍历字符串中的每个字符for char in s:if char in parenthesis_map:# 情况1:左括号→压入对应的右括号stack.append(parenthesis_map[char])else:# 情况2:右括号→验证匹配# 栈空(无左括号)或栈顶与当前右括号不匹配→无效if not stack or stack.pop() != char:return False# 3. 遍历结束后,栈为空→所有左括号均匹配;否则→存在未匹配左括号return len(stack) == 0# 测试示例(文档相关场景)
if __name__ == "__main__":test_cases = ["()[]{}",  # 有效(文档隐含正确案例)"([{}])",  # 有效(文档示例)"(]",      # 无效"([)]",    # 无效"{{{"      # 无效]for case in test_cases:print(f"字符串 '{case}' 是否有效:{is_valid_parentheses(case)}")# 输出结果:# 字符串 '()[]{}' 是否有效:True# 字符串 '([{}])' 是否有效:True# 字符串 '(]' 是否有效:False# 字符串 '([)]' 是否有效:False# 字符串 '{{{' 是否有效:False

四、栈的核心知识点小结

  1. 核心特性:仅栈顶操作、后进先出(LIFO),入栈 / 出栈时间复杂度 O (1);
  2. 实现方式
    • 数组实现:基于 Python 列表,简单直观,支持固定容量或动态扩容;
    • 链表实现:基于节点 + 引用,天然支持动态扩容,需处理指针逻辑;
  3. 典型应用:括号匹配(如 LeetCode 20)、表达式求值、函数调用栈、浏览器历史记录(前进 / 后退)等;
  4. 注意事项:操作前需判断栈空(避免栈下溢)或栈满(固定容量时,避免栈溢出)。
http://www.dtcms.com/a/430748.html

相关文章:

  • Java-Spring入门指南(十八)JSON字符串的解析与对象转换
  • JavaScript 严格模式
  • 数据时代的基石 —— 数据库的核心价值:MySQL 三大范式精讲
  • **跨平台开发:发散创新,探索无界限**随着技术的飞速发展,跨平台开发已经成为软件开发的必然趋势
  • 2025年中小工程企业成本管理新突破:如何选对管理软件?
  • JVM初始堆大小和最大堆大小多少合适?
  • 网站汉英结合的怎么做织梦欧美网站模板
  • 构建AI智能体:五十、ModelScope MCP广场 · MCP协议 · Cherry Studio:AI应用生产线
  • 从零开始:MCP数据库助手(二)- 核心功能实现
  • Django Admin 完全指南:内置功能、高级使用与第三方扩展
  • Django 路由详解
  • Django Admin 配置完全指南:从基础到高级实战
  • MySQL 全量 + 增量备份脚本(RPM 安装)实践与问题解析
  • 嘉兴网站建设方案外包运营推广公司
  • 第6章串数组:稀疏矩阵三元组顺序表的行逻辑连接顺序表
  • MATLAB仿真:编程基础实验全解析——从入门到实战
  • [特殊字符]灵感补给站 | pinterest 设计灵感分享 UI版面设计2
  • seo与网站建设php网站开发文档模板
  • GameObject 常见类型详解 -- 任务给予对象(QUESTGIVER)
  • docker部署mssql
  • 网站备案能查到什么wordpress关键字设置
  • LAMA(2014): 一项对SCADE模型进行基于SMT验证的开源方案
  • 从AGI到ASI演化的路径与启示
  • 重庆孝爱之家网站建设邢台是哪个省的城市
  • 【Linux学习笔记】线程概念和控制(二)
  • AES-128 CMAC:保障嵌入式通信安全的认证算法
  • Oumi:开源的AI模型一站式开发平台,涵盖训练、评估和部署模型
  • 大数据消息中间件选型终极指南:深度解析Kafka、Pulsar、RocketMQ架构与性能
  • 网站推广排名收费南昌做企业网站
  • 【Mosquitto的数据流程架构】