数据结构——栈和队列
创始人
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;
}

 结尾:

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

相关内容

热门资讯

安卓系统怎么关钥匙,轻松掌握钥... 手机里的安卓系统,是不是有时候让你觉得有点儿头疼?比如,当你想关掉手机,却发现钥匙在哪里呢?别急,今...
安卓系统有隐私空间,打造安全私... 你知道吗?在智能手机的世界里,安卓系统可是个超级明星呢!它不仅功能强大,而且现在还悄悄地给你准备了一...
安卓系统设置角标,打造专属通知... 你有没有发现,手机上的安卓系统设置里有个神奇的小功能——角标?这个小东西虽然不起眼,但作用可大了去了...
安卓系统定位信息查询,揭秘移动... 你有没有想过,你的手机里藏着多少秘密?尤其是那个安卓系统,它可是个超级侦探,随时随地都在帮你定位。今...
安卓刷入系统恢复,轻松实现设备... 手机系统崩溃了?别慌!安卓刷入系统恢复大法来啦! 手机,这个我们生活中不可或缺的小伙伴,有时候也会闹...
安卓系统限制无法录音,探索无法... 你有没有遇到过这种情况?手机里明明装了录音软件,却突然发现,哎呀妈呀,竟然无法录音了!这可真是让人头...
怎么降级手机系统安卓,操作指南... 手机系统升级了,新功能层出不穷,但有时候,你可能会觉得,这系统太卡了,想回到那个流畅如丝的年代。别急...
米oa系统是安卓系统吗,深入解... 亲爱的读者,你是否曾好奇过,米OA系统是不是安卓系统的一员?这个问题,就像是一颗好奇的种子,悄悄地在...
手机刷安卓车载系统,手机刷机后... 你有没有发现,现在开车的时候,手机和车载系统之间的互动越来越紧密了呢?想象当你驾驶着爱车,一边享受着...
vivo安卓怎么降系统,viv... 手机用久了,是不是觉得系统越来越卡,运行速度大不如前?别急,今天就来教你怎么给vivo安卓手机降降级...
nova 4刷安卓系统,体验全... 最近手机界可是热闹非凡呢!听说华为nova 4要刷安卓系统了,这可真是让人兴奋不已。你有没有想过,你...
如果当初没有安卓系统,科技世界... 想象如果没有安卓系统,我们的生活会是怎样的呢?是不是觉得有点不可思议?别急,让我们一起穿越时空,探索...
安卓电视装win系统,系统转换... 亲爱的读者们,你是否曾想过,在你的安卓电视上装一个Windows系统,让它瞬间变身成为一台功能强大的...
安卓手机还原系统好处,重拾流畅... 你有没有遇到过安卓手机卡顿、运行缓慢的情况?别急,今天就来给你揭秘一下安卓手机还原系统的那些好处,让...
安卓系统能跑win吗,探索跨平... 你有没有想过,你的安卓手机里能不能装上Windows系统呢?这听起来是不是有点像科幻电影里的情节?别...
安卓车载系统蓝牙设置,畅享智能... 你有没有发现,现在开车的时候,手机和车载系统之间的互动越来越频繁了呢?这不,今天就来给你详细说说安卓...
奥利奥安卓系统,探索新一代智能... 你有没有想过,一块小小的奥利奥饼干竟然能和强大的安卓系统扯上关系?没错,今天就要来聊聊这个跨界组合,...
微信使用安卓系统,功能解析与操... 你有没有发现,现在用微信的人越来越多了呢?尤其是安卓系统的用户,简直就像潮水一样涌来。今天,就让我带...
体验最新原生安卓系统,极致体验... 你有没有想过,手机系统就像是我们生活的调味品,有时候换一种口味,生活都会变得有趣起来呢?最近,我体验...
安卓系统能玩原神,尽享奇幻冒险... 你有没有想过,在安卓系统上也能畅玩《原神》这样的热门游戏呢?没错,就是那个画面精美、角色丰富、玩法多...