数据结构——栈和队列
创始人
2025-05-30 07:05:13

作者:几冬雪来

时间:2023年3月18日

内容:数据结构栈和队列的基础讲解

目录

前言: 

1.栈的概念及结构: 

2.栈的插入和删除:

3.栈的实现:

1.创建文件:

2.静态栈的实现: 

3.栈的结构体:

4.栈的初始化: 

5.释放栈: 

6.扩容操作: 

7.取出栈顶元素: 

8.返回下标个数:

9.访问栈顶元素: 

10.实践:

11.代码: 

 结尾:


前言: 

在这篇博客之前,我们将数据结构中的链表部分内容讲解完毕,那么在链表完结后,我们又很快进入数据结构中的另一个板块的学习了,板块名为——栈和队列

1.栈的概念及结构: 

既然这一篇讲述的内容是栈与队列,那么一开始我们就要先了解它们是什么东西。首先来说一说——。 

栈:栈是一种特殊的线性表,先比较与链表的可以进行头插或者尾插操作不一样,它只允许进行固定一端的插入或者删除元素的操作,栈中的数据元素遵守后进先出的原则,插入元素的操作我们称为——入栈/压栈/进栈,删除元素的操作被我们称为——出栈

2.栈的插入和删除:

了解到了栈基本信息后,这里我们就画一个图来讲解一下栈的插入和删除。

这就是我们的入栈和出栈的原理图。从图可以看出,在栈中进行数据插入和删除操作的一端被我们称为栈顶出数据和入数据都在栈顶进行,这也符合我们后进先出的原则

这里我们依靠栈来举例子,正常来说我们往栈里面插入数据1,2,3,到时候栈里面进行删除的话就是反过来3,2,1的依次删除。 

那么这里问一个问题,我们的栈的出栈形式只有这一种固定的结果吗?那肯定不是的,栈的入栈和出栈形式有很多种,而它们的结果也不一样

依旧以1,2,3来举例,我们先依次进栈,再依次出栈,这是我们的一种结果。

类似我们上图就是另外一种结果,入栈同样是1,2,3。但是这次我们不再全部入栈完再依次出栈,在这里我们对一个值先入栈后执行出栈的操作,然后接下来再入栈另一个值。这种一边入栈一边出栈的操作,最后我们的结果不是3,2,1而是1,2,3。同时这里也可以变为先入栈1,2,然后2进行出栈操作,下来再入栈3,最后全部出栈,这又是一种新的结果

3.栈的实现:

讲了那么多栈的基本内容,接下来我们就来实现栈。而在我们的数据结构中,数组和链表都可以用作栈的实现。而在实现栈的过程中,在前面两者之间我们优先使用数组形式。因为对比链表,数组中的元素是连续的,也比较符合我们上方栈的图像。

1.创建文件:

栈的实现和我们的顺序表与链表一样,一开始都是要创建多个文件。

这里还是创建一个.h文件和两个.c文件。 

2.静态栈的实现: 

因为在栈的实现中我们优先选取的是数组形式,那么这里就延伸出来了——静态栈这一个操作,那么我们的静态栈又是怎么实现的? 

在这里简简单单进行一个初始化,因为是多个变量,因此我们还是创建一个结构体来保存我们的数据。 

在结构体我们我们创建一个数组来存放我们的元素,top为我们的下标,capacity为我们元素的个数。 

3.栈的结构体:

但是在日常中,我们并不怎么使用静态的栈。那么不用数组初始化而是用指针初始化我们的结构体代码需要怎么修改一下呢?

与上面相同,op为我们的下标,capacity为我们元素的个数,只不过这里将原先的数组替换成为了指针。 

4.栈的初始化: 

栈的结构体书写完了之后,接下来要对其进行使用的话,首先就要对其初始化,那它是怎么样初始化的呢? 

 

这里在一开始我们就断言,而后先为我们的栈开辟一块空间,如果开辟失败我们这里要进行一个报错提醒。既然开辟了4个整形大小,那么capacity元素的个数也要初始化为4,top对应下标初始化为0。 

5.释放栈: 

既然我们要使用栈的话,在使用之后将其释放也是我们必不可少的一个步骤。 

 

这里也是非常的简单,直接free掉a然后将其置空,又因为置空了,所以这里的capacity和top都要改为0。 

6.扩容操作: 

既然我们上面在进行初始化的时候用到了malloc函数,那么肯定就存在着内存不够需要扩容的情况。 

 

还是断言先,接下来判断,如果我们下标的值和capacity相等,说明我们的空间满了需要对其扩容。扩容的代码就不多讲了,如果扩容成功的话这里就将新创建的指针交给ps->a进行维护,又因为扩容了原先的两倍所以capacity乘等于2。如果不需要扩容的话,这里就将x的值给数组下标为ps->top的位置,然后ps->top进行++即可

7.取出栈顶元素: 

在前面提到了,有入栈的操作那自然也会有出栈的操作。这个操作也就类似我们删除数组的尾元素。 

 

 

这里需要两个断言,一个来判断ps为不为空,另一个则是用来判断我们的下标,如果ps->top不为0则不会报错,如果二者都为真的话,我们这里直接让ps->top--即可,并不用将它释放置空。 

8.返回下标个数:

如果这里我们要查在这里我们应该有多少个元素的话该怎么办?

 

这里也是十分的简单,直接断言后返回即可。 

9.访问栈顶元素: 

如果我们要打印数据的话,那就要一个一个的访问栈顶的元素,而后将栈顶的元素删除。 

 

因为在之前的程序中,我们将ps->top加到了栈顶的下一个位置,所以这里需要进行-1操作才能访问我们栈顶的元素。开始依旧要进行断言操作。

10.实践:

在这里我们输入几个值来实现一下操作。

 

这种就是我们的依次入栈完了之后再依次出栈的操作结果。如果我们想要里面某个值入栈后马上进行出栈的操作又要怎么搞?

 

11.代码: 

Stack.c文件

#include "Stack.h"void STInit(ST* ps)
{assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){perror("malloc fail");return;}ps->capacity = 4;ps->top = 0;//top栈顶元素的下一个位置//ps->top = -1;top栈顶元素的位置
}//释放栈
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);if (ps->a == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity *= 2;}ps->a[ps->top] = x;ps->top++;
}void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}int STSize(ST* ps)
{assert(ps);return ps->top;
}bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}

 Sack.h文件

#pragma once#include 
#include 
#include 
#include typedef int STDataType;#define N 10typedef struct Stack
{int *a;int top;//下标int capacity;
}ST;void STInit(ST* ps);
void STDestroy(ST* ps);void STPush(ST* ps,STDataType x);
void STPop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
STDataType STTop(ST* ps);

test.c文件

#include "Stack.h"int main()
{ST st;STInit(&st);STPush(&st, 1);STPush(&st, 2);printf("%d ", STTop(&st));STPop(&st);STPush(&st, 3);STPush(&st, 4);printf("%d ", STTop(&st));STPop(&st);STPush(&st, 5);while (!STEmpty(&st)){printf("%d ", STTop(&st));STPop(&st);}STDestroy(&st);return 0;
}

 结尾:

到这里,我们栈的基础操作就已经实现和书写完毕了,但是这并不是结束,接下来我们还会对栈进行更加深入的了解和学习。在往后的一些题目当中,有一些也会用到我们栈与队列的知识去解决,最后希望这篇博客可以为各位栈与队列的部分的学习开一个头。 

相关内容

热门资讯

【实验报告】实验一 图像的... 实验目的熟悉Matlab图像运算的基础——矩阵运算;熟悉图像矩阵的显示方法࿰...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
大模型落地比趋势更重要,NLP... 全球很多人都开始相信,以ChatGPT为代表的大模型,将带来一场NLP领...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
kuernetes 资源对象分... 文章目录1. pod 状态1.1 容器启动错误类型1.2 ImagePullBackOff 错误1....
STM32实战项目-数码管 程序实现功能: 1、上电后,数码管间隔50ms计数; 2、...
TM1638和TM1639差异... TM1638和TM1639差异说明 ✨本文不涉及具体的单片机代码驱动内容,值针对芯...
Qt+MySql开发笔记:Qt... 若该文为原创文章,转载请注明原文出处 本文章博客地址:https://h...
Java内存模型中的happe... 第29讲 | Java内存模型中的happen-before是什么? Java 语言...
《扬帆优配》算力概念股大爆发,... 3月22日,9股封单金额超亿元,工业富联、鸿博股份、鹏鼎控股分别为3.0...
CF1763D Valid B... CF1763D Valid Bitonic Permutations 题目大意 拱形排列࿰...
SQL语法 DDL、DML、D... 文章目录1 SQL通用语法2 SQL分类3 DDL 数据定义语言3.1 数据库操作3.2 表操作3....
文心一言 VS ChatGPT... 3月16号,百度正式发布了『文心一言』,这是国内公司第一次发布类Chat...
CentOS8提高篇5:磁盘分...        首先需要在虚拟机中模拟添加一块新的硬盘设备,然后进行分区、格式化、挂载等...
Linux防火墙——SNAT、... 目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条...
部署+使用集群的算力跑CPU密... 我先在开头做一个总结,表达我最终要做的事情和最终环境是如何的,然后我会一...
Uploadifive 批量文... Uploadifive 批量文件上传_uploadifive 多个上传按钮_asing1elife的...
C++入门语法基础 文章目录:1. 什么是C++2. 命名空间2.1 域的概念2.2 命名...
2023年全国DAMA-CDG... DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义...
php实现助记词转TRX,ET... TRX助记词转地址网上都是Java,js或其他语言开发的示例,一个简单的...
【分割数据集操作集锦】毕设记录 1. 按要求将CSV文件转成json文件 有时候一些网络模型的源码会有data.json这样的文件里...
Postman接口测试之断言 如果你看文字部分还是不太理解的话,可以看看这个视频,详细介绍postma...
前端学习第三阶段-第4章 jQ... 4-1 jQuery介绍及常用API导读 01-jQuery入门导读 02-JavaScri...
4、linux初级——Linu... 目录 一、用CRT连接开发板 1、安装CRT调试工具 2、连接开发板 3、开机后ctrl+c...
Urban Radiance ... Urban Radiance Fields:城市辐射场 摘要:这项工作的目标是根据扫描...
天干地支(Java) 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:...
SpringBoot雪花ID长... Long类型精度丢失 最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数...
对JSP文件的理解 JSP是java程序。(JSP本质还是一个Servlet) JSP是&#...
【03173】2021年4月高... 一、单向填空题1、大量应用软件开发工具,开始于A、20世纪70年代B、20世纪 80年...
LeetCode5.最长回文子... 目录题目链接题目分析解题思路暴力中心向两边拓展搜索 题目链接 链接 题目分析 简单来说࿰...