学习笔记——栈

栈(Stack)

一、栈的定义与特性

定义

栈是限定仅在表尾进行插入和删除操作的线性表。

特性

  • 先进后出(FILO - First In Last Out)

  • 后进先出(LIFO - Last In First First)

核心概念

  • 栈顶(Top):允许操作的一端

  • 栈底(Bottom):不允许操作的一端

  • 入栈(Push):向栈顶添加元素

  • 出栈(Pop):从栈顶移除元素

二、两种"栈"的区别与联系

数据结构中的栈

// 链式栈示例

typedef struct stacknode {

DATATYPE data;

struct stacknode *next;

} LinkStackNode;

  • 内存位置:堆空间(动态分配)

  • 适用场景:更广泛,可自定义大小

  • 操作方式:通过指针操作

系统栈(调用栈)

  • 内存位置:0~3G内存中的一段(通常约8M)

  • 存储内容:

  1. 函数的调用关系

  2. 局部变量

  3. 参数

  4. 返回地址

  • 工作原理:同样遵循先进后出原则

共同点

  • 都遵循先进后出原则

  • 都有入栈(push)和出栈(pop)操作

三、栈的存储方式

1. 顺序存储(数组实现)

  • 使用连续内存空间

  • 需要预分配固定大小

  • 操作简单,效率高

2. 链式存储(链表实现)

// 链栈节点结构

typedef struct stacknode {

DATATYPE data; // 数据域

struct stacknode *next; // 指针域

} LinkStackNode;

// 链栈结构

typedef struct {

LinkStackNode *top; // 栈顶指针

int clen; // 栈长度

} LinkStack;

四、栈的分类(按增长方向)

根据栈指针移动方向,栈可分为4种类型:

|-----|---------|----------|------------|
| 类型 | 名称 | Top指针指向 | 新增元素后Top变化 |
| 空增栈 | 空栈+地址增加 | 新元素待插入位置 | 地址增大 |
| 空减栈 | 空栈+地址减少 | 新元素待插入位置 | 地址减小 |
| 满增栈 | 满栈+地址增加 | 最后入栈的元素 | 地址增大 |
| 满减栈 | 满栈+地址减少 | 最后入栈的元素 | 地址减小 |

关键区别:

  • 增栈:新增元素后,Top指针指向的内存地址慢慢变大

  • 减栈:新增元素后,Top指针指向的内存地址慢慢变小

  • 空栈:Top指针指向新元素待插入的位置

  • 满栈:Top指针指向最后入栈的元素的位置

五、栈的基本操作接口

链栈操作函数

// 创建栈

LinkStack* CreateLinkStack();

// 入栈操作

int PushLinkStack(LinkStack* ls, DATATYPE* newdata);

// 出栈操作

int PopLinkStack(LinkStack* ls);

// 获取栈顶元素

DATATYPE* GetTopLinkStack(LinkStack* ls);

// 获取栈大小

int GetSizeLinkStack(LinkStack* ls);

// 判断栈是否为空

int IsEmptyLinkStack(LinkStack* ls);

// 销毁栈

int DestroyLinkStack(LinkStack* ls);

六、栈的应用场景

1. 递归问题

  • 函数调用栈本身就是栈的应用

  • 保存函数调用现场,确保正确返回

2. 回溯问题

  • 深度优先搜索(DFS)

  • 路径记录和回退

3. 表达式求值

  • 中缀转后缀表达式

  • 运算符优先级处理

4. 括号匹配检查

  • 检查括号是否成对出现

  • 检查嵌套是否正确

5. 浏览器历史记录

  • 前进/后退功能

  • 页面访问历史管理

七、相关数据结构对比

双向链表 vs 栈

// 双向链表节点(对比)

typedef struct dounode {

DATATYPE data;

struct dounode *prev; // 前驱指针

struct dounode *next; // 后继指针

} DouLinkNode;

// 栈节点(对比)

typedef struct stacknode {

DATATYPE data;

struct stacknode *next; // 只有后继指针

} LinkStackNode;

主要区别:
访问方式:
  • 栈:只能从栈顶访问(受限)

  • 双向链表:可从任意位置访问(灵活)

操作限制:
  • 栈:只能在表尾操作

  • 链表:可在任意位置插入删除

实现复杂度:
  • 栈:实现简单

  • 链表:实现相对复杂

八、栈的适用原则

何时使用栈?

  • 需要"撤销"操作时

  • 需要记录历史状态时

  • 问题具有递归特性时

  • 需要反转数据顺序时

  • 检查嵌套结构时

栈的优势

  • 操作简单:只有push和pop

  • 效率高:时间复杂度O(1)

  • 内存可控:链栈动态分配,不浪费空间

  • 逻辑清晰:先进后出,易于理解

九、实际编程示例

表达式求值栈示例

// 使用两个栈:数字栈和运算符栈

LinkStack* num_stack = CreateLinkStack(); // 数字栈

LinkStack* op_stack = CreateLinkStack(); // 运算符栈

// 扫描表达式

while (表达式未结束) {

if (是数字) {

PushLinkStack(num_stack, &数字);

} else if (是运算符) {

// 处理优先级

while (栈顶运算符优先级 >= 当前运算符) {

// 弹出运算

弹出两个数字和一个运算符;

计算结果;

结果入数字栈;

}

PushLinkStack(op_stack, &运算符);

}

}

十、 总结要点

  • 栈的本质:受限的线性表,只能在表尾操作

  • 核心特性:先进后出(FILO/LIFO)

  • 两种实现:顺序存储(数组)和链式存储(链表)

  • 四种分类:空增栈、空减栈、满增栈、满减栈

  • 应用广泛:递归、回溯、表达式求值、括号匹配等

  • 系统对比:数据结构栈(堆空间) vs 系统栈(内存固定区域)

相关推荐
叶小鸡30 分钟前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
昵称小白1 小时前
复杂度分析方法
算法
我的xiaodoujiao1 小时前
API 接口自动化测试详细图文教程学习系列16--项目实战演练3
python·学习·测试工具·pytest
科研前沿1 小时前
2026 数字孪生前沿科技:全景迭代报告 —— 镜像视界生成式孪生(Generative DT)技术白皮书
大数据·人工智能·科技·算法·音视频·空间计算
时空系1 小时前
第10篇:继承扩展——面向对象编程进阶 python中文编程
开发语言·python·ai编程
复利人生 复利日知录 赋能循环2 小时前
2026年复利精进:我的每日觉醒与成长密码
学习·思维模型·知识复利·复利·独立
sakiko_2 小时前
UIKit学习笔记4-使用UITableView制作滚动视图
笔记·学习·ios·swift·uikit
CHANG_THE_WORLD3 小时前
python 批量终止进程exe
开发语言·python
古城小栈3 小时前
从 cargo-whero 库中,找到提升 rust 的契机
开发语言·后端·rust