数据结构——栈的概念理解与代码实现

鱼眼双目测距实战:从OpenCV标定到SGBM匹配的完整流程解析 本文详细解析了鱼眼双目测距的完整流程,从OpenCV标定到SGBM匹配,涵盖标定、校正、匹配和测距四个关键阶段。通过实战经验分享,帮助开发者解决鱼眼镜头强畸变带来的测距挑战,提升测距精度至5%以内。特别适合机器人导航、自动驾驶和VR领域的开发者参考。 阅读详情

栈(Stack)

栈是一口只能从顶部开口的桶:最后放进去的盘子必须最先拿出来,后进先出(LIFO),像叠罗汉一样只能动最上面那个。

核心思想

栈是受限的线性表:只允许在一端(栈顶)做插入(压栈 Push)和删除(出栈 Pop),另一端(栈底)封死。这种「只能动一端」的限制反而造就了它独特的适用场景——凡是需要回溯、撤销、嵌套匹配、深度优先的地方,栈几乎都是首选。

我用动态数组实现栈(也可以用链表):

  • arr:动态数组,存数据。
  • top:栈顶标记,约定指向栈顶元素的下一个空位(初始 0)。
  • capacity:当前容量。

top 的两种约定对比:

约定初始值栈顶元素元素个数空栈判断
指向栈顶下一个空位(本项目)0arr[top-1]toptop == 0
指向栈顶元素-1arr[top]top+1top == -1

本项目用第一种(top=0),好处:元素个数直接等于 top,STSize 直接返回 top,空栈判断 top==0。代价:取栈顶要 arr[top-1]。

数据结构定义

typedef struct stack
{
    STDataType *arr;   // 动态数组
    int top;           // 指向栈顶下一个空位
    int capacity;      // 容量
}ST;

内存模型(压了 1,2,3,top=3,capacity=4):

arr -> [ 1 ][ 2 ][ 3 ][   ]
        0    1    2    3
                  ↑    ↑
               栈顶  top=3(下一个写入位)
                    capacity=4
只能从 top 这一端进出,底端(下标0)封死

关键操作实现

初始化 STInit

void STInit(ST *pst)
{
    pst->arr = NULL;       // 延迟分配
    pst->top = 0;          // 指向栈顶下一个空位
    pst->capacity = 0;
}

逐行解释:和顺序表一样延迟分配,top=0 表空栈。capacity 必须归零,否则第一次 Push 时 top==capacity 判断失效,跳过扩容直接写 NULL。

入栈 STPush

void STPush(ST *pst, STDataType x)
{
    assert(pst);
    if (pst->top == pst->capacity)    // 栈满,扩容
    {
        int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;
        STDataType *tmp = (STDataType *)realloc(pst->arr, newcapacity*sizeof(STDataType));
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(1);    // 扩容失败必须终止,否则下面写入空指针段错误
        }
        pst->arr = tmp;
        pst->capacity = newcapacity;
    }
    pst->arr[pst->top++] = x;    // 在 top 位写入,top 再+1
}

逐行解释:和顺序表 SLCheckcapacity + SLPushBack 一模一样的套路。先判满扩容,用 tmp 接 realloc 防失败泄漏,扩容失败 exit(1) 终止。

修复前的 bug:原来扩容失败只 return,但函数没真正退出(return 在 if 内确实会返回函数),可是——等等,return 后函数确实返回了,不会执行到 pst->arr[pst->top++]。那 bug 在哪?问题在于 pst->arr 此时仍是旧指针(扩容前),如果旧容量已满,top==capacity,arr[top] 越界写。更隐蔽的是:扩容失败时旧内存还在但已满,继续写入是越界。改成 exit(1) 最干脆——内存都申请不到,程序没救了。

pst->arr[pst->top++] = x:后置++,先在 top 位写,再 top+1,指向新的空位。

出栈 STPop

void STPop(ST *pst)
{
    assert(pst);
    assert(pst->top > 0);    // 空栈不能出
    pst->top--;              // 逻辑删除,top 往下移一格
}

逐行解释:出栈只需 top--,把「栈顶」下移一位。原 arr[top-1] 的数据还在内存里,但逻辑上已出栈,下次 Push 会覆盖它——惰性删除,O(1) 且不碰内存。assert(top > 0) 防止空栈出栈导致 top 变 -1(下溢),后续 arr[-1] 越界。

判空 STEmpty

bool STEmpty(ST *pst)
{
    assert(pst);
    return pst->top == 0;    // top==0 即空栈
}

逐行解释:直接比较 top,O(1)。

取栈顶 STTop

STDataType STTop(ST *pst)
{
    assert(pst);
    assert(pst->top > 0);    // 空栈没有栈顶
    return pst->arr[pst->top - 1];    // top 指向空位,栈顶是 top-1
}

逐行解释:因为 top 指向「栈顶下一个空位」,真正的栈顶元素在 arr[top-1]。assert(top>0) 保证 top-1 >= 0,避免 arr[-1] 越界。

易错点:忘了 -1,直接 arr[top] 读到的是未初始化的空位(垃圾值)。这是 top=0 约定下最常见的错。

求大小 STSize

int STSize(ST *pst)
{
    assert(pst);
    return pst->top;    // top 恰好等于元素个数
}

逐行解释:top=0 约定的红利——元素个数就是 top,直接返回。

销毁 STDestroy

void STDestroy(ST *pst)
{
    free(pst->arr);            // 释放动态数组
    pst->arr = NULL;           // 置空防悬空
    pst->capacity = pst->top = 0;
}

逐行解释:释放数组,置空指针和计数器。栈的 ST 结构体通常由调用者在栈上定义(如 ST st;),所以只释放内部的 arr,不动 pst 本身。

复杂度分析

操作时间复杂度说明
入栈 Push均摊 O(1)扩容时 O(n),均摊后常数
出栈 PopO(1)只改 top
取栈顶 TopO(1)数组下标访问
判空 / 求大小O(1)比较 top
销毁O(1)只 free 一次(数组整体释放)

栈的所有核心操作都是 O(1),这是它高效的根本。

常见陷阱清单

  1. top 约定混淆:top=0 取栈顶用 arr[top-1],top=-1 用 arr[top],两者代码完全不同,混用必错。
  2. 空栈出栈不判空 → top 下溢为 -1,越界。
  3. 扩容失败处理不当 → 继续写入导致越界/段错误。
  4. #define N 10; 残留:头文件里这行多了分号且 N 从未使用,是垃圾代码(虽不影响编译,但不规范)。
  5. 用 free 删栈顶:栈是惰性删除,Pop 不该 free,否则 arr 整块内存被破坏。

我的实现 vs 教科书实现

  • 整体标准:动态数组实现,扩容、判空、取顶齐全。
  • 残留垃圾:Stack.h 第 8 行 #define N 10; 多分号且无用,应删除。
  • 缺接口:没有 STClear(清空不销毁)。
  • top 两种约定:代码注释保留了 top=-1 的写法作为对照,便于理解约定差异。
  • vs 链式栈:数组栈 cache 友好、实现简单;链式栈无扩容问题但每节点有指针开销。

拓展知识点

变体与进阶

  • 链式栈:用单链表头插/头删实现(头做栈顶),避免扩容,但每节点多一个指针。
  • 共享栈:两个栈共享一个数组,一个从底增长一个从顶增长,省空间,适合两个栈使用率互补的场景。
  • 单调栈:维护单调递增/递减序列,O(n) 解决「下一个更大元素」「柱状图最大矩形」等问题,是面试高频考点。
  • 函数调用栈:程序运行时的调用栈本质就是栈结构,递归就是压栈,返回就是出栈,栈溢出 = 递归太深。

常见考点(必刷)

  • 括号匹配:左括号压栈,右括号弹栈匹配,栈空即匹配成功。
  • 表达式求值:中缀转后缀(调度场算法),后缀求值,都靠栈。
  • DFS 非递归:用栈模拟递归的调用过程。
  • 浏览器前进/后退:两个栈,一个存后退历史一个存前进历史。
  • 两个栈实现队列:一个栈入、一个栈出,出栈为空时把入栈全部倒过来。

与其他结构的关系

栈是受限线性表,和队列(FIFO)是对照结构。栈可用顺序表或链表实现(本项目用顺序表/数组)。栈是递归、DFS、表达式处理的基础设施。两个栈可以模拟队列,两个队列也能模拟栈(但效率不同)。

一句话记忆法

栈:后进先出(LIFO),只动栈顶一端;top=0 约定下栈顶是 arr[top-1],个数就是 top,出栈只 top-- 不 free。


#DataStructure #CS #Stack #LIFO #受限线性表

CloudCompare点云变换保姆级教程:从平移、旋转到绕任意点旋转,一次搞定 本文提供CloudCompare点云变换的全面教程,涵盖从基础平移、旋转到绕任意点旋转的高级技巧。通过详细的操作步骤和实战案例,帮助用户掌握点云数据处理的核心技能,提升三维模型对齐和变换的效率与精度。 阅读详情

相关推荐

记录LeNet的硬件加速器设计(一)

LeNet的硬件加速器设计实现。

2301_81029398的博客 3543

< 数据结构 > 栈的实现

前言 栈的概念 栈的结构 栈的实现 创建栈结构 初始化栈 销毁栈 入栈 出栈 获取栈顶元素 获取栈中有效元素个数 检测栈是否为空 总代码 Stack.h 文件 Stack.c 文件 Test.c 文件

bit_zyx的博客 2462

ANSYS Discovery 2023R1 保姆级教程:手把手教你玩转几何模型参数化(附避坑指南)

本文提供ANSYS Discovery 2023R1几何模型参数化的全面教程,涵盖基础环境搭建、核心操作解析及高级应用场景。重点讲解参数化建模中的常见问题与避坑方案,帮助用户高效掌握Workbench与Discovery的协同使用技巧,提升工程仿真效率。

weixin_29204205的博客 752

数据结构——栈和队列

本文详细介绍的栈和队列的实现方式,更是重点提到了4个关于栈和队列的OJ题:分别是设计循环队列,用栈实现队列,用队列实现栈,有效的括号。

fax_player的博客 6219

人工智能训练师技能等级认定四级技能考核试卷-样题4

本文为人工智能训练师四级技能考核试卷,包含六个实操考核项目,总时长150分钟。考核内容涵盖:1)车牌数据集规范评估与格式处理;2)车牌数据集采集代码修改与数据处理;3)房价预测数据集加载、预处理与可视化分析;4)车牌标注数据集审核与修正;5)螺丝螺母检测数据集的平台创建与共享;6)螺丝螺母数据的去噪处理与标注优化。要求考生使用Python编程、数据处理平台和标注工具完成各项任务,重点考察数据加载、格式转换、缺失值处理、数据可视化、标注审核及平台操作等技能。所有操作需在配备Python3.7和深度学习平台的W

weixin_42221934的博客 348

5G移动网络运维(优化)

5G 网络优化现状 移动通信行业属于技术密集型行业,是国民经济的重要支柱以及整个社会经济运转体系中不可或缺的基础。2019 年年底 5G 开始商用,截止到 2020 年3月,我国三大运营商建设了 16.1 万个 5G 基站,我国成为目前全球 5G 基站最多的国家。预计到 2020 年年底,我国运营商会建设大概 70 万个 5G 基站。基于 5G高频段的特性,信号覆盖距离会低于ins 基站,再加上 5G 万物互联的巨大经济潜力价值需求,后续三大运营商在 5G 基站建设数量上势必会超过当前 LTE 基站数量的

2301_78171382的博客 1325

【数据结构与算法】栈的介绍与实现(详解)

【本节目标】 1.1栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫做出栈。出数据也在栈顶

平淡中造就不平凡 684

Neo4j Desktop新手必看:3分钟搞定CSV数据导入(附常见报错解决方案)

本文详细介绍了在Neo4j Desktop中高效导入CSV数据的三种主流方法,包括图形化界面操作、命令行批量导入和Python驱动编程导入,并提供了常见报错解决方案和性能优化技巧,帮助新手快速构建知识图谱。

lambda的博客 648

数据结构栈的简单实现(JAVA)

新的改变 栈是线性数据结构的一种,相当于一个箱子,如果向往箱子里放书,第一本书肯定是放入箱底,但是取出来的时候是从最上面开始取的,并拿不到最里面的东西,所以元素是先进后出的,栈最上面的元素为栈顶元素。 以下是基于数组对栈的简单实现 package com.jym.stack; public class MyStack { private int[] elements; //初始化数组 ...

jym的博客 1万+

ABAP Cloud:面向云时代的 ABAP 开发范式与实践指南

摘要: 本文系统讲解SAP ABAP Cloud开发模型,涵盖其架构、工具链、规范及实践。ABAP Cloud作为统一开发模型,支持在SAP BTP和S/4HANA上构建云就绪应用,遵循clean core原则,通过RAP(RESTful应用编程模型)实现低耦合扩展。文章详细解析其核心构成(RAP、稳定API、clean core约束)、工具链(ADT、软件物流)及两种典型扩展场景(on-stack与side-by-side),并附可运行RAP示例代码(如销售笔记应用)。重点强调通过规范开发确保系统可升级性

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 402

【DaVinci Developer专题】-36-创建一个“既读又写”的Sender Receiver Port(SR PR-Port)

有时会遇到SWC需要对一个Port进行“既可以读,也可以写”的操作。以下图为例,Test_A_SWC中Test_A_Port是P-Port;Test_B_SWC中Test_A_Port是R-Port。Test_C_SWC需要对Test_A_Port同时进行“读”和“写”。 该篇将详细介绍PR-Port的创建方法。 目录 1 创建一个S/R Port Interface 2 将一个PR-Port端口添加至Application Component 3 PR-Port端口初始化 4 Run.

「汽车电子助手」的博客 3013

数据结构之栈的实现

数据结构之栈的实现

Ly的博客 1283

MNI152 坐标空间和 fsaverage 坐标空间相互转换, 如已知fsaverage空间的坐标如何求MNI152 坐标?aparc.a2009s.annot转化到MNI152空间?

大多数神经影像学研究的结果是在体积(例如,MNI152)或表面(例如,fsaverage)坐标系中报告的。体积坐标系和表面坐标系之间的准确映射可以促进许多应用,例如将 fMRI 组分析从 MNI152 投影到 fsaverage 以进行可视化或从 fsaverage 投影静息状态 fMRI 分区对 MNI152进行新数据的体积分析。Wu et al., 2018 评估了三种在 MNI152通过模拟上述应用的 Colin27 和 fsaverage 坐标系:将组平均数据从 MNI152/Colin27 投影到

从事脑科学核磁共振方法学研究,在Nature communications等权威期刊发表研究论文,熟练掌握磁共振处理方法和统计学方法,欢迎大家和我交流。 2966

《数据结构》之链栈

链栈 废话不多说,直接上代码实现。 #include <iostream> #define OK 1 #define ERROR 0 using namespace std; typedef int SElemType; typedef int Status; typedef struct StackNode { SElemType data; struct StackNode *next; }StackNode, *LinkStack; ...

M2534474759的博客 258

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

数据结构之栈的顺序存储结构及实现(C语言)

文章目录概念进栈出栈变化形式栈的顺序存储结构进栈操作出栈操作顺序栈代码 概念 栈(stack)是限定仅在表头和表尾进行插入和删除操作的线性表。 我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(Last in First Out)的线性表,简称LIFO结构。 理解: 首先栈是一个线性结构,也就是说栈元素具有线性关系,即前驱后继关系。只不过栈是一种特殊的线性表而已。 它的特殊之处就在于限制了这个线性表的插入和删除的位置,它始终只在栈顶

xiangjunyes的博客 4417

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

栈的介绍与实现(详解)

文章目录栈的介绍栈的概念栈的结构栈的实现初始化栈销毁栈入栈出栈获取栈顶元素检测栈是否为空获取栈中有效元素个数 栈的介绍 栈的概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈:栈的插入操作叫做进栈 / 压栈 / 入栈。(入数据在栈顶) 出栈:栈的删除操作叫做出栈。(出数据也在栈顶) 栈的结构 栈的实现 初始化栈 首先,我们需要用结构体创建一个栈,

2021dragon的博客 1761

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【C语言】基本数据结构-栈(链表实现和数组实现)

本文描述了栈的优点以及如何用链表和数组去实现栈。

weixin_43949948的博客 1074

数据结构:栈 ADT :使用链表实现对栈的基本操作。

数据结构:栈,及对栈的基本操作 这一篇博客呢,博主会针对栈这个东西,以及我们使用链表对栈的最基本操作进行一系列讲解。这部分内容博主会将其归到数据结构一框中,改框架还会不断更新。 目录↓ 1.栈模型 2.栈的基本操作 3.初总结 栈模型 说到栈,这个熟悉又陌生的字眼,我们在很多地方见过他,却不知道它到底是什么。其实它~并不复杂。 栈:限制插入和删除只能在一个位置进行的表。 说白了,如果我们是...

qq_45804132的博客 721

数据结构-栈

1.概念 栈是一种先进先出的数据结构,其中有两个关键的位置:栈顶和栈底。当需要出栈时,只需将栈顶元素取出并将原来的栈顶元素指针向前移动。压栈时,只需将栈顶位置指向新的元素。具体的示意图如下: 栈的实现可以基于两种常见的数据结构:数组和链表 2. 栈的实现 2.1 基于数组 示意图: 代码实现(java版): public class ArrayStack { private Objec...

missv5的博客 316

数据结构--栈和队列(详解+代码实现

/获取栈中有效元素个数。2.队中的元素不做修改,只能在队头删除,队尾增加元素。1.先进入栈的元素 会放在栈的底部。

2302_81153999的博客 1067

数据结构与算法-07(栈)

栈 个人博客:www.xiaobeigua.icu 1.1 栈概述 生活中的栈 存储货物或供旅客住宿的地方,可引申为仓库、中转站 。例如我们现在生活中的酒店,在古时候...

小北呱的博客 179

java 栈 先进后出_数据结构: 先进后出——堆栈

栈是一种常用的数据结构,在生活中经常遇到这样的例子,如铁路调度站。本节将详细介绍堆栈的实现过程。算法点拨(顺序栈)栈是一种重要的数据结构。从数据结构的角度看,栈也是线性表,其特殊性在于栈的基本操作是线性表操作的子集,它们是操作受限的线性表,因此可以称为限定性的数据结构。其操作是限定在表尾进行插入和删除操作,允许操作的一端称为栈顶。栈的结构如图11.09所示:图11.09 栈的结构实现栈首先需要实现...

weixin_42458937的博客 1871

PHP数据结构与算法:栈

一、概念 栈(stack),也有人称为堆栈,是一种容器,可存入数据元素、访问元素、删除元素。它的特点在于只能允许在容器的一端栈顶(top)进行数据加入(push)和数据输出(pop)的运算。没有了位置概念,保证任何时候可以操作的元素都是此前最后存入的那个元素,确定了一种默认的访问顺序。 ...

chuangqudiao9845的博客 163

TypeScript实现数据结构(一)栈,队列,链表

最近在学习typescript,就想着用typescript自己练习一些基本的数据结构,记录一下,读者有什么想法和建议也可以交流一下。 栈 class Stack&lt;T&gt;{ private items = null; constructor() { this.items = new Array&l...

weixin_33836223的博客 1037

数据结构:顺序栈与链式栈,链式栈的代码实现

本文章介绍了栈的概念、栈的逻辑结构、栈的存储结构、线性栈与链式栈、链式栈的代码实现等。有需要的可以参考下。

weixin_57535837的博客 1036

【数据结构从青铜到王者】第四篇:数据结构之栈

系列文章目录 文章目录系列文章目录前言一、栈的概念及结构1.栈的概念2.栈的结构二、栈的实现1.定义数组动态增长的栈struct Stack2.初始化栈StackInit函数3.销毁栈StackDestroy函数4.入栈StackPush函数5.出栈StackPop函数6.获取栈顶数据StackTop函数7.判断栈是否为空StackEmpty函数8.求出栈的大小StackSize函数总结 前言 一、栈的概念及结构 1.栈的概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行.

森明帮大于黑虎帮的博客 1781
上一篇: 数据结构——队列的概念解析与核心代码
下一篇: 不打断心流的翻译:QuickTranslate,让翻译从一个动作开始
DDXYcoder
博客等级 码龄1年 140粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值