数据结构之栈的讲解(源代码+图解+习题)
我们在学习过顺序表和链表之后,了解了使用数组存储数据,使用结构体来存储数据和有关的指针,这些都是底层的东西,链表是靠指针的链接,顺序表是靠数组的下标才能得以实现增删查改。众多数据结构其实底层都离不开数组,指针和结构体,今天我们要学习的栈也不例外,话不多说,直接上正菜!
1. 栈的概念:
在这里我先给大家栈的图解,通过图来理解概念。
1.1 栈的组成
栈:黑色边框及其内部空间为栈
栈顶:开口的方向叫做栈顶
栈底:闭口的方向叫做栈底
栈内元素:蓝色长方形

1.2 栈的进出规则(先进后出)
首先,我们往栈里存入或者删除数据的时候,只能在栈顶操作,也就是咱们俗话说的,从栈顶这一头进行增删的操作,那么我们入栈的顺序是1-2-3-4的时候,出栈的顺序就是4-3-2-1了。
我们不可以在栈底或者中间直接拿出来数据,只能在栈顶拿,谁在栈顶先拿谁,肯定是最后入栈的数据在栈顶。
所以栈的进出规则是 先进后出

2. 栈的底层架构的选择
我们知道,栈的进出规则是先进后出,我们秉持着这一理念就可以在顺序表或者链表中进行改造增删查改的规则,使其变成栈。那我们该如何选择呢?是选择顺序表还是链表呢?
2.1 栈的架构为顺序表(文末有源码,是使用方案)
2.1.1 栈和顺序表的比对
首先我们看一下用顺序表来构造栈是如何构造的。
当我们的栈是顺序表构造的时候,我们会发现栈底就是顺序表的表头,栈顶是顺序表的表尾。那通过顺序表如何对栈进行插入数据和删除数据呢?

2.1.2 栈的插入图解
我们对栈的插入,一定是在栈顶这边插入,那我们对比一下这两张图,在栈顶插入就相当于顺序表的尾插对吧!我们只需要尾插顺序表就可以完成栈的插入元素了。

2.1.3 栈的删除
栈是只能对栈顶进行增加和删除的,所以我们只能在栈顶删除元素,那是不是就相当于顺序表的尾删。
所以对于栈的删除,我们只需要尾删顺序表就可以了。

2.2 栈的架构为链表
而当我们使用链表作为栈的架构,什么样的链表才可以使栈的增添和删除容易呢?让我们看图一起寻找吧!
2.2.1 单链表构造栈(舍弃方案)
当我们使用单链表构造栈的时候,栈的插入和删除都相当于对单链表的尾部进行操作,插入还好,直接尾插就行,而删除的话,删除当前节点就找不到前一个节点了,我们还需要保存前一个节点,这样很麻烦,所以这个方案是舍弃的。

2.2.2 双向链表构造栈(舍弃方案)
对于双向链表很明显是比单链表好用,在出栈的操作,我们应该先保存栈顶元素的下一个元素的位置,也就是我们要删除图中的3,应该先保存2的位置,如果我们不保存2的位置,直接删除3,那么就找不到2的位置了。所以保存2的位置之后,删除3,再将指向3的指针 重新指向2就可以了。这个方法很明显比单链表好用,但是都没有顺序表构造的栈更方便直接,大家可以下去尝试使用双向链表模拟实现栈。

最后下面我们来用代码模拟一下栈,这里首推顺序表。
3. 栈的模拟实现(源代码)
3.1 栈的定义
typedef int STDataType;
//用顺序表模拟栈
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
3.2 栈的初始化
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}
3.3 栈的销毁
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
3.4 入栈
void STPush(ST* ps, STDataType x)
{assert(ps);// 11:40if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}ps->a = tmp;ps->capacity = newCapacity;}ps->a[ps->top] = x;ps->top++;
}
3.5 取栈顶元素
STDataType STTop(ST* ps)
{assert(ps);// assert(ps->top > 0);return ps->a[ps->top - 1];
}
3.6 出栈
void STPop(ST* ps)
{assert(ps);// assert(ps->top > 0);--ps->top;
}
3.7 栈的元素个数
int STSize(ST* ps)
{assert(ps);return ps->top;
}
3.8 栈是否为空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}
3.9 用到的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
以上就是栈的模拟实现了,下面我们做几个关于栈的习题。
4. 栈的习题
4.1 下列关于栈的叙述正确的是( )
A.栈是一种“先进先出”的数据结构
B.栈可以使用链表或顺序表来实现
C.栈只能在栈底插入数据
D.栈不能删除数据
答案:B
A错误:栈是一种先进后出的数据结构,队列是先进先出的。
B正确:顺序表和链表都可以用来实现栈,不过一般都使用顺序表,因为顺序表简单。
C错误:栈只能在栈顶进行输入的插入和删除操作。
D错误:栈是有入栈和出栈的操作,出栈就是从栈中删除一个元素。
4.2 一个栈的入栈序列为ABCDE,则不可能的出栈序列为( )
A.ABCDE
B.EDCBA
C.DCEBA
D.ECDBA
答案:D
画图解决问题
4.3. 链栈与顺序栈相比,比较明显的优点是( )
A.插入操作更加方便
B.删除操作更加方便
C.入栈时不需要扩容
答案:C
A错误,如果是链栈,在入栈的时候,直接尾插就行了,跟顺序栈没有多大区别。
B错误,如果是链栈,在出栈的时候,需要继续前一个节点的位置才行,要不然无法继续出栈, 而顺序栈则可以通过下标快速找到。链表的操作比顺序表复杂,因此使用顺序结构实现栈更简单。
C正确:链式结构实现栈时,每次入栈相当于链表中头插一个节点,没有扩容一说。
以上就是本次博文的分享,谢谢大家支持!
相关文章:
数据结构之栈的讲解(源代码+图解+习题)
我们在学习过顺序表和链表之后,了解了使用数组存储数据,使用结构体来存储数据和有关的指针,这些都是底层的东西,链表是靠指针的链接,顺序表是靠数组的下标才能得以实现增删查改。众多数据结构其实底层都离不开数组&…...
内网渗透-内网信息收集
内网信息收集 前言 当我们进行外网信息收集,漏洞探测以及漏洞利用后,获得了主机的权限后,我们需要扩大渗透的战果时,这是我们就要进行内网的渗透了,内网渗透最重要的还是前期的信息收集的操作了,就是我们的…...
LeetCode解法汇总2520. 统计能整除数字的位数
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 描述: 给你一个整…...
Lua语言编写爬虫程序
以下是一个使用luasocket-http库和Lua语言编写的爬虫程序。此程序使用了https://www.duoip.cn/get_proxy的代码。 -- 引入所需的库 local http require("socket.http") local ltn12 require("ltn12") local json require("json") -- 获取…...
安防监控项目---概要
文章目录 前言一、项目需求二、环境介绍三、关键点四、主框架分析总结 前言 各位小伙伴,在蛰伏了将近有半年的时间又要和大家分享新的知识了,这次和大家分享的是一个项目,因此呢我准备分项目阶段去和大家分享,希望大家都能够在每…...
数仓经典面试题
1.什么是数据仓库?请谈谈你对数据仓库的理解。 数据仓库是一个用于存储和管理数据的系统,它可以将分散的、异构的数据源中的数据进行抽取、转换、清洗和整合,然后按照一定的模型和架构进行组织和存储,以便更好地支持决策分析和业…...
【ARM Coresight 系列文章 15.2 – components power domain 详细介绍】
文章目录 1.1. Coresight 电源域模型1.1.1 CDBGPWRUPREQ 和 CDBGPWRUPACK1.1.2 CSYSPWRUPREQ 和 CSYSPWRUPACK1.1.3 Power Domain ID In RomTable1.1.4 Power domain entries1.1.5 Algorithm to discover power domain IDs1.1.6 Debug power requests1.1.7 System power reques…...
Flutter Android IOS 获取通讯录联系人列表
1.在pubspec.yaml 文件中添加 contacts_service 和 permission_handler 插件的依赖: dependencies:contacts_service: ^0.6.3 #获取联系人permission_handler: ^11.0.1 #权限请求2.在你的 Dart 代码中,导入 contacts_service 插件: impo…...
Spring Boot集成SpringFox 3.0与Pageable参数处理
Springfox 3.0有多个模块,提供了spring boot starter,与Spring Boot集成时仅需引入springfox-boot-starter,如下: <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter<…...
2、基于pytorch lightning的fabric实现pytorch的多GPU训练和混合精度功能
文章目录 承接 上一篇,使用原始的pytorch来实现多GPU训练和混合精度,现在对比以上代码,我们使用Fabric来实现相同的功能。关于Fabric,我会在后续的博客中继续讲解,是讲解,也是在学习。通过fabric,可以减少代码量&#…...
python版opencv人脸训练与人脸识别
1.人脸识别准备 使用的两个opencv包 D:\python2023>pip list |findstr opencv opencv-contrib-python 4.8.1.78 opencv-python 4.8.1.78数据集使用前一篇Javacv的数据集,网上随便找的60张图片,只是都挪到了D:\face目录下方便遍历 D:\face\1 30张刘德华图片…...
计算机视觉-数学基础*变换域表示
被研究最多的图像(或任何序列数据)变换域表示是通过傅 里叶分析 。所谓的傅里叶表示就是使用 正弦函数的线性组合来表示信号。对于一个给定的图像I(n1,n2) ,可以用如下方式分解它(即逆傅里叶变换): 其中&a…...
小程序如何设置自取规则
在小程序中,自取规则是指当客户下单时选择无需配送的情况下,如何设置相关的计费方式、指定时段费用、免费金额、预定时间和起取金额。下面将详细介绍如何设置这些规则,以便更好地满足客户的需求。 在小程序管理员后台->配送设置->自…...
Elasticsearch分词器-中文分词器ik
文章目录 使用standard analysis对英文进行分词使用standard analysis对中文进行分词安装插件对中文进行友好分词-ik中文分词器下载安装和配置IK分词器使用ik_smart分词器使用ik_max_word分词器 借助Nginx实现ik分词器自定义分词网络新词 ES官方文档Text Analysis 使用standard…...
ITSS信息技术服务运行维护标准符合性证书申请详解及流程
ITSS信息技术服务运行维护标准符合性证书 认证介绍 ITSS(InformationTechnologyServiceStandards,信息技术服务标准,简称ITSS)是一套成体系和综合配套的信息技术服务标准库,全面规范了IT服务产品及其组成要素,用于指导实施标准化…...
Inbound marketing的完美闭环:将官网作为营销枢纽,从集客进化为入站
Inbound marketing即入站营销的运作方式不同于付费广告,你需要不断地投入才能获得持续的访问量。而你的生意表达内容一经创建、发布,就能远远不断地带来流量。 Inbound marketing也被翻译作集客营销,也就是美国知名的营销SaaS企业hubspot所主…...
SQL On Pandas最佳实践
SQL On Pandas最佳实践 1、PandaSQL1.1、PandaSQL简介1.2、Pandas与PandaSQL解决方案对比1.3、PandaSQL支持的窗口函数1.4、PandaSQL综合使用案例2、DuckDB2.1、DuckDB简介2.2、SQL操作(SQL On Pandas)2.3、逻辑SQL(DSL on Pandas)2.4、DuckDB on Apache Arrow2.5、DuckDB …...
如何批量给视频添加logo水印?
如果你想为自己的视频添加图片水印,以增强视频的辨识度和个性化,那么你可以使用固乔剪辑助手软件来实现这一需求。下面就是详细的操作步骤: 1.下载并打开固乔剪辑助手软件,这是一款简单易用的视频剪辑软件,功能丰富&am…...
数据挖掘和大数据的区别
数据挖掘 一般用于对企业内部系统的数据库进行筛选、整合和分析。 操作对象是数据仓库,数据相对有规律,数据量较少。 大数据 一般指对互联网中杂乱无章的数据进行筛选、整合和分析。 操作对象一般是互联网的数据,数据无规律,…...
Go之流程控制大全: 细节、示例与最佳实践
引言 在计算机编程中,流程控制是核心的组成部分,它决定了程序应该如何根据给定的情况执行或决策。以下是Go语言所支持的流程控制结构的简要概览: 流程控制类型代码if-else条件分支if condition { } else { }for循环for initialization; con…...
DAMO-YOLO实战:用AI视觉系统做内容安全审核与统计
DAMO-YOLO实战:用AI视觉系统做内容安全审核与统计 1. 引言:当AI视觉遇见内容安全 在数字内容爆炸式增长的今天,如何高效地进行内容审核成为许多平台面临的挑战。传统人工审核不仅效率低下,而且容易因疲劳导致误判。本文将介绍如…...
gemeni 生成图片的提示词
[System / Prompt]You are an illustration assistant specialized in creating hand-drawn cartoon-style infographics. Follow all rules below strictly and without deviation.🎨 STYLE RULES(风格规则)Use a pure hand-drawn illustrat…...
某高校学生考微软MOS认证加学分
临近毕业季,到底是谁的学分还没有修够?微软MOS认证证书也可以加学分,每天学习两个小时,一周就可以完成考试,当天就出证书!📌关于难度选择版本难度:2016 < 2019 < 365ÿ…...
从LLaVA到Stable Diffusion:多模态融合选拼接还是交叉注意力?一张图帮你做技术选型
多模态融合技术选型指南:拼接与交叉注意力的深度对比与实践策略 在构建现代多模态AI系统时,工程师们常常面临一个关键决策点:如何有效地融合来自不同模态的信息?想象一下,你正在开发一个智能医疗影像分析系统ÿ…...
零基础学编程:借助快马与claude code生成交互式代码示例入门javascript
最近刚开始学习JavaScript,发现数组操作是编程中最基础也最常用的部分。作为一个完全零基础的小白,我尝试用InsCode(快马)平台结合Claude Code来学习这个知识点,整个过程比想象中顺利很多。这里记录下我的学习过程,希望能帮到同样…...
永磁同步电机全速域无位置传感器控制策略仿真研究:高频注入与改进滑膜控制方法应用
40、永磁同步电机全速域无位置传感器控制仿真(仿真代码参考文献说明文档) 主要内容: 采用高频注入改进滑膜控制方法,PMSM矢量控制仿真 [1]零低速域,采用无数字滤波器高频方波注入法,减少滤波的相位影响&…...
3分钟快速上手:免费高效的Elasticsearch可视化工具Elasticvue终极指南
3分钟快速上手:免费高效的Elasticsearch可视化工具Elasticvue终极指南 【免费下载链接】elasticvue Elasticsearch gui for the browser 项目地址: https://gitcode.com/gh_mirrors/el/elasticvue 你是否曾经为复杂的Elasticsearch集群管理而烦恼?…...
用LVGL玩转嵌入式UI:5个实战控件代码详解(按钮/滑块/图片/标签/开关)
LVGL嵌入式UI开发实战:五大核心控件深度解析与代码优化 在资源受限的嵌入式设备上实现流畅美观的用户界面,一直是开发者面临的挑战。LVGL(Light and Versatile Graphics Library)作为一款轻量级开源图形库,凭借其丰富的…...
多智能体协作四大架构模式:Subagents/Skills/Handoffs/Router完全指南
← 上一篇:AI大模型3月终局:商业化转向、智能体崛起与安全红线 → 下一篇:大模型推理加速2026:从500ms到80ms的完整优化路径 摘要 当单个 AI Agent 无法高效处理复杂任务时,多智能体系统(Multi-Agent Sys…...
医学图像分类实战:基于kvasir v2胃病数据集的深度卷积网络性能对比
1. 医学图像分类与KVASIR V2数据集简介 胃镜图像分类是计算机辅助诊断系统中的关键环节。KVASIR V2作为目前最全面的公开胃病数据集,包含8类常见胃部病变的8000张高清图像,每类1000张。这些图像由专业胃肠病专家标注,覆盖了从正常黏膜到早期…...
