【数据结构】千字深入浅出讲解栈(附原码 | 超详解)

🚀write in front🚀
📝个人主页:认真写博客的夏目浅石.
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:C语言实现数据结构
💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🖊
✉️如果无聊的话,就来逛逛我的博客栈吧stack-frame.cn
文章目录
- 前言
- 一、栈的概念
- 二、栈的结构
- 三、栈的实现
- 3.1 结构设计
- 3.2 接口总览
- 3.3 初始化
- 3.4 销毁
- 3.5 判断栈是否为空
- 3.6 入栈
- 3.7 出栈
- 3.8 取栈顶元素
- 3.9 计算栈的大小
- 四、 完整代码
- Stack.h
- Stack.c
- test.c
- 总结
前言
这几天看了数据结构的栈这一节,真的收获很大,第一次看没有动手敲代码就是感觉学了和没学一样,今天也是从新又看了一遍,并且边学边敲代码,终于算是非常理解栈这个东西了,今天就把我所学到的知识给大家分享一下。
一、栈的概念
栈 是一个特殊的 线性表
栈只允许在固定的一段进行插入和删除元素的操作。进行数据插入和删除操作的一端称为栈顶,不进行操作的一端称为栈底
栈中的元素遵守 后进先出 (LIFO - Last In First Out) 的原则。也就是先进的后出,后进的先出
栈对于数据的管理主要有两种操作:
- 压栈:栈的插入操作叫做进栈 / 压栈 / 入栈,从栈顶进行压栈。
- 出栈:栈的删除操作叫做 出栈,从栈顶进行出栈。

二、栈的结构
栈一般可以使用 数组或链表 实现。让我们分析一下使用这两种方法实现,栈的结构分别是什么样的。
在分析之前,我们要明确的一点是,栈只对 栈顶 的元素进行操作。
那么对于 顺序栈 和 链式栈 ,那个更加好呢?那必定是 顺序栈,因为使用顺序栈的 尾插尾删非常方便, 且 cpu缓存利用率也更高。而且对于顺序栈实现起来相对简单,所以我们接下来就实现 顺序栈 。
三、栈的实现
3.1 结构设计
我们既然是实现 顺序栈,那么它的结构肯定就和 顺序表 差不多:
typedef struct Stack
{STDatatype* a; // 指向动态开辟的数组int capacity; // 栈的容量int top; // 标识 栈顶的下一个位置的下标 或 栈顶的下标
}ST;
这里的 top 我们需要好好理解一下。当top的初始值不同时,top可以表示 栈顶的下一个位置的下标 或 栈顶下标。
- 当
top = 0,top表示栈顶的下一个位置的下标:

2. 当 top = -1,top 表示栈顶的下标:

top 初始值为 -1,那么需要先 ++top,再压栈。否则会越界。当 最后一次压栈时,为先 ++top 再压栈,top 最后的位置就是栈顶的下标处。
3.2 接口总览
void StackInit(ST* ps); // 初始化
void StackDestroy(ST* ps); // 销毁
void StackPush(ST* ps, STDatatype x); // 压栈
void StackPop(ST* ps); // 出栈
STDatatype StackTop(ST* ps); // 取栈顶元素
bool StackEmpty(ST* ps); // 判空
int StackSize(ST* ps); // 计算栈的大小
3.3 初始化
我们实现的是顺序栈,那么就和顺序表一样,需要创建结构体变量,传结构体的地址,进行初始化。
在初始化的时候就给栈开上四个单位的空间,并且将起始容量设定为4。
注意了我们这里设定的 top = 0,那么表示 top 为栈顶的下一个位置的下标。
void StackInit(ST* ps)
{// 结构体一定不为空,所以需要断言assert(ps);ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);if (ps->a == NULL){perror("malloc fail");exit(-1);}ps->capacity = 4;ps->top = 0;
}
3.4 销毁
对于栈的销毁,那么我们就只需要释放动态开辟的空间,将指针置空。并将 capacity 和 top 两个变量置 0即可。
void StackDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}
3.5 判断栈是否为空
我们起初设定 top = 0,所以判断栈是否为空,那么只需要看 top 是否为0就可以了。如果为0,返回真 ;不为0,返回假。
bool StackEmpty(ST* ps)
{assert(ps);// 如果 ps->top == 0,返回真// 如果 ps->top !=0,返回假return ps->top == 0;
}
3.6 入栈
void StackPush(ST* ps, STDatatype x)
{assert(ps);// 检查容量if (ps->top == ps->capacity){STDatatype* tmp = (STDatatype*)realloc(ps->a, sizeof(STDatatype) * ps->capacity * 2);if (tmp == NULL){perror("realloc fail");exit(-1);}ps->a = tmp;ps->capacity *= 2;}// 插入元素// top 为栈顶的下一个元素// 先插入再 ++ ps->a[ps->top] = x;ps->top++;
}
3.7 出栈
void StackPop(ST* ps)
{assert(ps);// 如果栈空,则不能删除assert(!StackEmpty(ps));ps->top--;
}
3.8 取栈顶元素
STDatatype StackTop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}
3.9 计算栈的大小
int StackSize(ST* ps)
{assert(ps);return ps->top;
}
四、 完整代码
Stack.h
#pragma once#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>typedef int STDatatype;typedef struct Stack
{STDatatype* a;int capacity;int top; // 初始为0,表示栈顶位置下一个位置下标// 初始为-1,表示栈顶位置的下标
}ST;void StackInit(ST* ps);
void StackDestroy(ST* ps);
void StackPush(ST* ps, STDatatype x);
void StackPop(ST* ps);
STDatatype StackTop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);
Stack.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "Stack.h"// top 为栈顶 初识值为 -1void StackInit(ST* ps)
{// 结构体一定不为空assert(ps);ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);if (ps->a == NULL){perror("malloc fail");exit(-1);}ps->capacity = 4;ps->top = -1;
}void StackDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}void StackPush(ST* ps, STDatatype x)
{assert(ps);// 检查容量// 此时 top 一开始为 -1,不能表示栈中元素的数目// top + 1 才是正确的if (ps->top + 1 == ps->capacity){STDatatype* tmp = (STDatatype*)realloc(ps->a, sizeof(STDatatype) * ps->capacity * 2);if (tmp == NULL){perror("realloc fail");exit(-1);}ps->a = tmp;ps->capacity *= 2;}// 插入元素// top 为栈顶元素// 先 ++ 再插入ps->a[++ps->top] = x;
}void StackPop(ST* ps)
{assert(ps);// 如果栈空,则不能删除assert(!StackEmpty(ps));ps->top--;
}STDatatype StackTop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top];
}bool StackEmpty(ST* ps)
{assert(ps);return ps->top == -1;
}int StackSize(ST* ps)
{assert(ps);return ps->top + 1;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "Stack.h"void TestST1()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);StackPush(&st, 5);StackPop(&st);StackPop(&st);printf("%d\n", StackTop(&st));
}int main()
{TestST1();
}
总结
今天学习了栈的知识,初次写数据结构的知识,给我的感觉就是,学三遍不如手敲代码一遍来的实在,所以数据结构的学习我将多画图,多敲代码来学习,希望大家吸取经验和我一起学习数据结构,为后面打比赛刷题打下坚实基础。
我是夏目浅石,希望和你一起学习进步,刷题无数!!!希望各位大佬能一键三连支持一下博主,hhhh~我们下期见喽

如果无聊的话,就来逛逛我的博客栈吧stack-frame.cn
✨原创不易,还希望各位大佬支持一下\textcolor{blue}{原创不易,还希望各位大佬支持一下}原创不易,还希望各位大佬支持一下
👍 点赞,你的认可是我创作的动力!\textcolor{9c81c1}{点赞,你的认可是我创作的动力!}点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!\textcolor{ed7976}{收藏,你的青睐是我努力的方向!}收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!\textcolor{98c091}{评论,你的意见是我进步的财富!}评论,你的意见是我进步的财富!
相关文章:
【数据结构】千字深入浅出讲解栈(附原码 | 超详解)
🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:C语言实现数据结构 💬总结:希望你看完…...
自动驾驶V2X
1 SoC MDM9250 2 设备网络节点 mhi_swip0 rmnet_mhi0 3 网络协议栈log打印控制 include/linux/netdevice.h ethtool -s eth0 msglvl [level] ethtool -s eth0 msglvl 0x6001 4 URLs MHI initial design review https://lore.kernel.org/lkml/001601d52148$bd852840$388f78c0$c…...
零基础自学网络安全/渗透测试有哪些常见误区?
一、网络安全学习的误区 1.不要试图以编程为基础去学习网络安全 不要以编程为基础再开始学习网络安全,一般来说,学习编程不但学习周期长,且过渡到网络安全用到编程的用到的编程的关键点不多。一般人如果想要把编程学好再开始学习网络安全往…...
ConvMixer:Patches Are All You Need
Patches Are All You Need 发表时间:[Submitted on 24 Jan 2022]; 发表期刊/会议:Computer Vision and Pattern Recognition; 论文地址:https://arxiv.org/abs/2201.09792; 代码地址:https:…...
day10—编程题
文章目录1.第一题1.1题目1.2思路1.3解题2.第二题2.1题目2.2涉及的相关知识2.3思路2.4解题1.第一题 1.1题目 描述: 给定一个二维数组board,代表棋盘,其中元素为1的代表是当前玩家的棋子,0表示没有棋子,-1代表是对方玩…...
如何测量锂电池的电量
锂电池在放电时我们有时需要知道电池的实时电量,如电池电量低了我们就需要及时给锂电池充电,避免电池过度放电。我手里的这个就是个单节锂电池电量显示模块,只需要将这个模块接到锂电池的正负极即可显示电量。这个模块的电量分为四档…...
菜鸟刷题Day6
⭐作者:别动我的饭 ⭐专栏:菜鸟刷题 ⭐标语:悟已往之不谏,知来者之可追 一.链表内指定区间反转:链表内指定区间反转_牛客题霸_牛客网 (nowcoder.com) 描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转…...
DecimalFormat格式化显示数字
DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字,可以实现以最快的速度将数字格式化为你需要的样子。 DecimalFormat 类主要靠 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充, # 表示只要有可能就…...
cpu中缓存简介
一级缓存是什么: 一级缓存都内置在CPU内部并与CPU同速运行,可以有效的提高CPU的运行效率。一级缓存越大,CPU的运行效率越高,但受到CPU内部结构的限制,一级缓存的容量都很小。 CPU缓存(Cache Memory…...
【数据结构】二叉树的遍历以及基本操作
目录 1.树形结构 1.概念 2.二叉树 2.1概念 2.2 两种特殊的二叉树 2.3二叉树的存储 2.4二叉树的基本操作 1.手动快速创建一棵简单的二叉树 2.二叉树的遍历 (递归) 3.二叉树的层序遍历 4.获取树中节点的个数 5.获取叶子节点的个数 6.获取第K层节点的个数 7.获取二叉…...
若依框架 --- ruoyi 表格的设置
表格 字典值转换 (1) 方式1:使用字典枚举的方式 var isDownload [[${dict.getType(YES_OR_NO)}]];{field : isDownload,title : 是否允许下载,formatter: function(value, row, index) {return $.table.selectDictLabel(isDownload, value);} }, (2) 方式2&…...
“两会”网络安全相关建议提案回顾
作为新一年的政治、经济、社会等发展的“风向标”,今年“两会”在3月13日顺利闭幕。在今年“两会”期间,多位人大代表也纷纷围绕网络安全、数据安全的未来发展做了提案和建议。 01 “两会”网络安全相关建议和提案回顾 建议统筹智能网联汽车数据收集与共…...
一篇文章带你真正了解接口测试(附视频教程+面试真题)
目录 一、什么是接口测试? 二、为什么要做接口测试? 三、如何开展接口测试? 四、接口测试常见面试题 一、什么是接口测试? 所谓接口,是指同一个系统中模块与模块间的数据传递接口、前后端交互、跨系统跨平台跨数据…...
C/C++每日一练(20230325)
目录 1. 搜索插入位置 🌟 2. 结合两个字符串 🌟 3. 同构字符串 🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 搜索插入位置 给定一个排序数…...
Linux操作系统ARM指令集与汇编语言程序设计
一、实验目的1.了解并掌握ARM汇编指令集2.应用ARM指令集编写一个程序操控开发板上的LED灯二、实验要求应用ARM汇编指令集编写程序,实现正常状态下开发板上的LED灯不亮,按下一个按键之后开发板上的LED灯进入流水灯模式。三、实验原理四个LED灯的电路如下图…...
计网之HTTP协议和Fiddler的使用
文章目录一. HTTP概述和fidder的使用1. 什么是HTTP2. 抓包工具fidder的使用2.1 注意事项2.2 fidder的使用二. HTTP协议格式1. HTTP请求格式1.1 基本格式1.2 认识URL1.3 方法2. 请求报头关键字段3. HTTP响应格式3.1 基本格式3.2 状态码一. HTTP概述和fidder的使用 1. 什么是HTT…...
sql性能优化:MS-SQL(SQL Server)跟踪日志信息结果列字段说明,MSSQL的列字段说明(column)
sql性能优化:MS-SQL(SQL Server)跟踪日志信息结果列字段说明,MSSQL的列字段说明(column) 参考: SQL:BatchCompleted 事件类 | Microsoft Learn SQL 跟踪 | Microsoft Learn sp_trace_setevent (…...
DNS主从复制
#前提准备:关闭SElinux 关闭防火墙 时间同步 #环境说明:Centos7 #ip地址:dns-master:10.0.0.100 dns-slave:10.0.0.103 web:10.0.0.101 主DNS服务配置 1.安装软件包: yum install bind -…...
常见的js加密/js解密方法
常见的js加密/js解密方法 当今互联网世界中,数据安全是至关重要的。为了保护用户的隐私和保密信息,开发人员必须采取适当的安全措施。在前端开发中,加密和解密技术是一种常见的数据安全措施,其中 JavaScript 是最常用的语言之一。…...
6 python函数
函数 在实现某个功能对应的代码的时候,如果将实现功能对应的函数放到函数中,那么下一次再需要这个功能的时候,就可以不用再写这个功能对应的代码,直接调用这个功能对应的函数。 1.什么是函数 函数就是实现某一特点功能的代码的封装…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
