数据结构——栈和队列
创始人
2025-05-30 05:44:00
0

作者:几冬雪来

时间: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;
}

 结尾:

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

相关内容

热门资讯

武汉摩尔影城安卓系统APP,便... 你有没有想过,一部手机就能带你走进电影的世界,享受大屏幕带来的震撼?今天,就让我带你详细了解武汉摩尔...
联想刷安卓p系统,畅享智能新体... 你有没有发现,最近联想的安卓P系统刷机热潮可是席卷了整个互联网圈呢!这不,我就迫不及待地来和你聊聊这...
mac从安卓系统改成双系统,双... 你有没有想过,你的Mac电脑从安卓系统改成双系统后,生活会有哪些翻天覆地的变化呢?想象一边是流畅的苹...
kindke安卓系统激活码,激... 亲爱的读者,你是否在寻找一款能够让你手机焕然一新的操作系统?如果你是安卓用户,那么今天我要给你带来一...
萤石云监控安卓系统,安卓系统下... 你有没有想过,家里的安全可以随时随地掌握在手中?现在,有了萤石云监控安卓系统,这不再是梦想啦!想象无...
手机安卓系统会不会爆炸,系统升... 手机安卓系统会不会爆炸——一场关于安全的探讨在当今这个数字化的世界里,手机已经成为我们生活中不可或缺...
安卓系统双清详图解,恢复出厂设... 你有没有遇到过手机卡顿、运行缓慢的问题?别急,今天就来给你详细解析一下安卓系统的“双清”操作,让你的...
召唤抽奖系统安卓直装,轻松体验... 你知道吗?现在市面上有一种特别火的玩意儿,那就是召唤抽奖系统安卓直装。是不是听起来就让人心动不已?没...
系统工具箱安卓2.3,深度解析... 你有没有发现,手机里的那些小工具,有时候就像是个神奇的百宝箱呢?今天,就让我带你一探究竟,看看安卓2...
华硕平板安卓刷机系统,解锁性能... 亲爱的数码爱好者们,你是否曾为你的华硕平板安卓系统感到厌倦,想要给它来一次焕然一新的体验呢?那就跟着...
鸿蒙系统与安卓怎么区别,差异解... 你有没有发现,最近手机圈子里有个大热门,那就是鸿蒙系统和安卓系统的区别。这两位“系统大侠”各有各的绝...
红帽系统怎么刷回安卓,红帽系统... 你是不是也和我一样,对红帽系统刷回安卓充满了好奇?别急,今天就来给你详细揭秘这个过程,让你轻松上手,...
ios安卓联想三系统,全面解析... 你有没有发现,现在的手机市场真是热闹非凡呢!各种操作系统轮番登场,让人眼花缭乱。今天,就让我带你来聊...
安卓调用系统相机并存盘,And... 你有没有想过,手机里的照片和视频,是怎么被我们随手拍下,又神奇地存到手机里的呢?今天,就让我带你一探...
安卓4.0原生系统下,引领智能... 你有没有发现,安卓4.0原生系统下,手机的使用体验简直就像打开了新世界的大门?今天,就让我带你一起探...
安卓c13系统,创新功能与性能... 你知道吗?最近安卓系统又来了一次大更新,那就是安卓C13系统。这可不是一个小打小闹的更新,而是带来了...
鸿蒙3.0脱离安卓系统,开启全... 你知道吗?最近科技圈可是炸开了锅,因为华为的新操作系统鸿蒙3.0横空出世,竟然宣布要脱离安卓系统,这...
安卓怎么应对苹果系统,安卓系统... 你知道吗?在智能手机的世界里,安卓和苹果就像是一对相爱相杀的恋人。安卓系统,这位多才多艺的“大众情人...
安卓系统如何开橱窗教程,安卓系... 你有没有想过,你的安卓手机里也能开个橱窗,展示那些你心爱的宝贝?没错,就是那种可以随时翻看、随时分享...
安卓系统软件APK,深入探究安... 你有没有发现,手机里的那些好玩的应用,其实都是靠一个小小的文件来“住”进去的?没错,就是安卓系统里的...