数据结构——栈

栈是计算机领域最基础、最重要、应用最广 的线性数据结构,没有之一。相比于顺序表、链表偏向数据存储,栈更偏向逻辑规则,贯穿整个编程体系。

我们写代码的函数调用、递归执行、表达式运算、浏览器后退、编辑器撤销、操作系统内存分区,全部都依赖栈的核心特性。本文带你彻底吃透栈的底层原理、实现方式、操作逻辑、优缺点及实战场景,覆盖新手学习和面试高频考点。

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

1.1 什么是栈?

栈是一种受限的线性表,仅允许在表的一端进行插入和删除操作,另一端完全封闭,禁止任何操作。

它的核心规则只有一句话:后进先出(LIFO,Last In First Out)

通俗类比:弹夹

子弹压入弹夹(入栈),最后压进去的子弹,最先被打出去(出栈),最先压入的子弹只能最后出来,完美契合栈的特性。

1.2 栈的专属名词

  • 栈顶(top):唯一允许操作的一端,所有入栈、出栈操作都在这里完成

  • 栈底(bottom):封闭端,固定不变,不允许增删数据

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

  • 出栈(pop):删除栈顶元素

  • 取栈顶(top):获取栈顶元素,不删除、不修改栈结构

1.3 核心特点总结

  1. 严格遵循 后进先出 LIFO

  2. 不支持随机访问,无法直接查找中间、栈底元素

  3. 所有操作仅能作用于栈顶,时间复杂度极低

  4. 结构简单、执行效率极高,无多余遍历开销

二、栈的两种底层实现

栈是逻辑结构 ,底层物理存储依托两种基础线性结构实现:顺序栈(基于顺序表)链式栈(基于链表)。日常开发中,99% 的场景都使用顺序栈。

2.1 顺序栈(主流实现)

基于连续内存的顺序表实现,也就是 C++ 中 stack、Java Stack 的底层原理。

底层结构

依托连续内存空间,通过一个下标变量标记栈顶位置:

  • 数组/动态数组存储数据

  • top 变量:记录当前栈顶下标,初始为 -1(空栈)

  • 栈底固定在数组起始位置

核心操作逻辑
  • 入栈 push:top++,数据存入 top 下标位置,O(1)

  • 出栈 pop:top--,仅修改下标,无需删除数据,O(1)

  • 取栈顶:直接读取 top 下标数据,O(1)

手写简易顺序栈(C++)
cpp 复制代码
template<typename T>
class SeqStack {
private:
    vector<T> data;
public:
    // 入栈
    void push(const T& val) {
        data.push_back(val);
    }

    // 出栈
    void pop() {
        if(!empty()) data.pop_back();
    }

    // 获取栈顶元素
    T& top() {
        return data.back();
    }

    // 判断空栈
    bool empty() {
        return data.empty();
    }

    // 获取栈大小
    int size() {
        return data.size();
    }
};
顺序栈优缺点

✅ 优点:操作极快、缓存友好、实现简单、无指针开销

❌ 缺点:固定容量会栈溢出,动态扩容有少量内存开销

2.2 链式栈(基于链表实现)

基于单链表实现,为了保证 O(1) 效率,链式栈永远在链表头部做增删

如果在尾部操作需要遍历链表,效率会退化为 O(n),因此链式栈统一采用头插、头删。

核心操作
  • 入栈:头插新节点,更新栈顶指针

  • 出栈:删除头节点,更新栈顶指针

链式栈优缺点

✅ 优点:无容量限制,不会栈溢出,按需分配内存,无内存浪费

❌ 缺点">缓存不友好,每个节点有指针冗余,频繁 new/delete 有性能开销

结论:工业开发优先使用顺序栈

三、栈的四大核心操作(全 O(1))

栈是所有数据结构中操作效率最高的结构,所有常规操作时间复杂度均为 O(1),无遍历、无移动元素。

  1. push 入栈:栈顶添加元素

  2. pop 出栈:删除栈顶元素(不返回数据)

  3. top 取栈顶:获取栈顶元素(不删除)

  4. empty 判断空栈:判断栈是否无元素

重点区别:pop 只删除不返回,top 只读取不删除,开发中经常搭配使用:先 top 取值,再 pop 出栈。

四、栈的经典面试算法场景

栈的算法题是笔试、面试高频考点,核心解题思想全部依托「后进先出」特性。

4.1 括号匹配(最经典)

题目:判断 `()[]{}` 字符串是否合法匹配

思路:遇到左括号入栈,遇到右括号弹出栈顶比对,不匹配或栈非空即为非法。

4.2 表达式求值、逆波兰表达式

计算机无法直接识别中缀表达式,依靠栈实现:数字入栈,遇到运算符弹出两个数字计算,结果重新入栈。

4.3 字符串反转、单词反转

利用后进先出特性,全部入栈后依次出栈,自动完成反转。

4.4 单调栈(高频算法)

进阶栈用法:维护栈内元素单调递增/递减,可解决每日温度、下一个更大元素、柱状图最大矩形等经典难题。

五、栈在计算机底层的真实应用(重中之重)

很多新手只学数据结构栈,却不知道程序运行的栈内存,这是后端、操作系统、嵌入式必懂知识点。

5.1 函数调用栈(程序运行核心)

程序运行时,操作系统会开辟栈内存(虚拟内存),专门存放函数栈帧。

函数调用流程完全遵循栈规则:

  1. 调用新函数:新建栈帧,入栈

  2. 函数执行结束:栈帧销毁,出栈

main 函数最先入栈、最后出栈,完美契合后进先出。

栈溢出 StackOverflow:递归深度过大、局部变量过多,栈内存空间耗尽,程序崩溃。

5.2 递归实现原理

递归的本质就是函数栈帧的不断入栈与出栈,递归终止后逐层出栈回溯结果。

5.3 浏览器/软件操作逻辑

  • 浏览器后退页面:访问记录入栈,后退就是出栈

  • 编辑器 Ctrl+Z 撤销、Ctrl+Y 重做:双栈实现操作回退

5.4 编译器语法解析

编译器解析代码、判断语法合法性、运算表达式,底层全部依赖栈结构。

六、栈、顺序表、链表核心区别

很多新手容易混淆三者,一张表彻底分清:

数据结构 访问方式 增删效率 核心特点 用途
顺序表 随机访问 O(1) 中间增删慢 连续内存、查询快 存储大量数据、频繁查询
链表 顺序访问 O(n) 任意位置增删快 离散内存、动态灵活 频繁增删、动态扩容
仅访问栈顶 O(1) 栈顶增删极快 后进先出、受限操作 逻辑控制、算法、函数调用

七、全文总结(面试背诵版)

  1. 栈是**后进先出(LIFO)**的受限线性表,仅支持栈顶增删查,所有操作 O(1)。

  2. 底层分为顺序栈和链式栈,顺序栈缓存友好、效率更高,是工业主流实现。

  3. 核心操作:push 入栈、pop 出栈、top 取栈顶、empty 判断空栈。

  4. 算法场景:括号匹配、表达式求值、字符串反转、单调栈问题。

  5. 底层核心价值:支撑函数调用、递归执行、程序栈内存,是程序运行的基础数据结构。

相关推荐
iiiiyu12 小时前
面向对象案例
java·大数据·开发语言·数据结构·python·编程语言
奶人五毛拉人一块12 小时前
滑动窗口算法及习题讲解
数据结构·算法·滑动窗口·子数组
加油201912 小时前
嵌入式软件技术栈和学习路线详解
linux·arm开发·数据结构·mqtt·设计模式·嵌入式
是main不是漫12 小时前
【数据结构--双向链表】从前有个节点,它想要两头讨好…
c语言·数据结构·链表
南境十里·墨染春水12 小时前
数据结构——AVL二叉平衡树
数据结构
过期动态12 小时前
【RabbitMQ高级篇】生产者可靠性、MQ可靠性、消费者可靠性以及延迟队列的实现
java·数据结构·分布式·算法·rabbitmq·ruby
『昊纸』℃13 小时前
《C语言电子新-2026最新版》-编程语言与程序
数据结构·算法·程序设计·编程语言·软件开发
王璐WL21 小时前
【C语言入门级教学】函数的概念2
c语言·数据结构·算法
不知名的老吴1 天前
双栈秒杀表达式的生成方式
数据结构