【数据结构初阶】手把手带你实现栈
创始人
2024-05-27 20:08:41
0

前言

在进入数据结构初阶的学习之后,我们学习了顺序表和链表,当然栈也是一种特殊的数据结构,他的特点是后进先出。


栈的概念及结构

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

我们切记,此处的栈是数据结构中的栈,与我们操作系统处学习的栈是不同的,它是一个数据存储的位置,而这里的栈是数据存储时的结构,是两个学科中不同的术语。

栈的入数据叫做进栈,压栈或者入栈,出数据时叫做出栈,栈的压栈和出栈都是在栈顶操作的,所以符合后进先出或者先进后出。

我们的生活中就有很多关于栈的示例,比如我们在坐电梯的时候,后上来的人到达目的地之后先出电梯,先上来的人后出电梯。

栈的接口实现

我们在学习完顺序表和链表之后,我们就要考虑顺序表和链表的优劣点来实现栈,我们知道栈的入栈和出栈都是一端,所以可以使用顺序表的尾插和尾删,也可以使用链表的头插头删以及尾插尾删,但是在都可以实现的情况下,我们就要选择消耗最小的顺序表。

(1)定义结构体

typedef int datetype;typedef struct Stack
{datetype* a;int capacity;int top;
}stack;

我们使用typedef定义栈中存储数据的类型,这样方便我们在日后的使用中进行修改,我们将栈的结构定义为一个动态的顺序表,通过a指针来控制,同时记录栈顶的位置,以及最大容量。 

(2)栈的初始化

void stackInit(stack* p)
{assert(p);p->a = NULL;p->capacity = 0;p->top = 0;
}

对p进行断言,能够防止不小心传入NULL后解引用程序崩溃,初始化各个数据。

(3)压栈

void stackPush(stack* p,datetype x)
{assert(p);if (p->capacity == p->top){int newCapacity = p->capacity == 0 ? 4 : 2 * p->capacity;datetype* tmp = (datetype*)realloc(p->a, newCapacity * sizeof(datetype));if (tmp == NULL){perror("realloc");exit(-1);}p->a = tmp;p->capacity = newCapacity;}p->a[p->top] = x;p->top++;
}

同理,对指针p进行断言,判断栈顶是否达到最大容量处,如果没有到达直接将数据插入到top处,并且top自加,如果到了最大容量,我们就对顺序表进行扩容,首先判断容量是否为0,为0时将容量扩到4个数据的字节数,否则容量乘2。

此处的压栈与顺序表的尾插相同。

(4)出栈

void stackPop(stack* p)
{assert(p);assert(!stackEmpty(p));p->top--;
}

 同理对指针进行断言,还需要注意的时需要判断顺序表是否为NULL,如果为空,解引用后程序会崩溃,所以我们选择粗暴的方式进行断言,然后对栈顶减1,不用去处理本来的数据。

(5)判空

bool stackEmpty(stack* p)
{assert(p);return p->top==0;
}

此处我们只想要判断栈顶处是否为0,如果为0则说明顺序表为空,否则顺序表不为空,我们使用了bool类型,C语言中并没有布尔类型,所以我们要引头文件

(6)求栈顶元素

datetype stackTop(stack* p)
{assert(p);assert(!stackEmpty(p));return p->a[p->top-1];
}

断言p以及断言顺序表不为空,返回栈顶的值即可。

(7)求数据个数 

int stackSize(stack* p)
{assert(p);return p->top;
}

(8)销毁栈

void stackDestroy(stack* p)
{assert(p);free(p->a);p->a = NULL;p->capacity = 0;p->top = 0;
}

我们使用malloc,calloc,realloc申请的空间,我们都必须使用free进行销毁。


源码 

stack.h

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#includetypedef int datetype;typedef struct Stack
{datetype* a;int capacity;int top;
}stack;
//初始化
void stackInit(stack* p);
//销毁
void stackDestroy(stack* p);
//入栈
void stackPush(stack* p, datetype x);
//出栈
void stackPop(stack* p);
//取栈顶数据
datetype stackTop(stack* p);
//数据个数
int stackSize(stack* p);
//判断是否为空
bool stackEmpty(stack* p);

stack.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void stackInit(stack* p)
{assert(p);p->a = NULL;p->capacity = 0;p->top = 0;
}
void stackPush(stack* p,datetype x)
{assert(p);if (p->capacity == p->top){int newCapacity = p->capacity == 0 ? 4 : 2 * p->capacity;datetype* tmp = (datetype*)realloc(p->a, newCapacity * sizeof(datetype));if (tmp == NULL){perror("realloc");exit(-1);}p->a = tmp;p->capacity = newCapacity;}p->a[p->top] = x;p->top++;
}void stackPop(stack* p)
{assert(p);assert(!stackEmpty(p));p->top--;
}void stackDestroy(stack* p)
{assert(p);free(p->a);p->a = NULL;p->capacity = 0;p->top = 0;
}datetype stackTop(stack* p)
{assert(p);assert(!stackEmpty(p));return p->a[p->top-1];
}bool stackEmpty(stack* p)
{assert(p);return p->top==0;
}
int stackSize(stack* p)
{assert(p);return p->top;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void test()
{stack st;stackInit(&st);stackPush(&st, 1);stackPush(&st, 2);stackPush(&st, 3);stackPush(&st, 4);printf("%d ", stackTop(&st));stackPop(&st);printf("%d ", stackTop(&st));stackPop(&st);stackPush(&st, 5);stackPush(&st, 6);//int ret = stackTop(&st);//printf("%d", ret);while (!stackEmpty(&st)){printf("%d ",stackTop(&st));stackPop(&st);}stackDestroy(&st);}int main()
{test();return 0;
}

通过测试,我们发现无论什么时候出栈,出几个数据,都符合栈的特点,先进后出,后进先出。


总结 

今天我通过顺序表的结构来实现了栈,向展示并讲解了栈的概念、结构与各接口的实现过程与作用原理,当然也可以通过链表的方式来实现,希望大家可以多多尝试。

相关内容

热门资讯

61寸的手机安卓系统,安卓系统... 你有没有想过,如果手机屏幕大到像电视一样,那会是怎样的体验呢?想象61寸的手机安卓系统,是不是瞬间觉...
电脑安卓什么系统好用点,电脑端... 你有没有想过,家里的电脑换成安卓系统会是什么样子?是不是觉得这俩家伙天生八字不合,其实啊,现在市面上...
如何鉴别苹果是安卓系统,如何辨... 你有没有想过,你的手机里那些可爱的应用,它们到底是在苹果的iOS系统里欢快地跳着舞,还是在安卓的大家...
安卓手机查看出厂系统,从生成到... 你有没有想过,你的安卓手机里隐藏着一段不为人知的秘密历史呢?没错,就是它的出厂系统!今天,就让我带你...
安卓系统可用画画软件,激发创意... 你有没有想过,在手机上也能轻松画出心中的世界呢?没错,就是那种可以随时随地拿起手机,就能挥洒创意的画...
安卓系统的问卷调查,洞察用户需... 你知道吗?最近我在网上看到了一份关于安卓系统的问卷调查,结果简直让人大开眼界!这不,我就迫不及待地想...
深度os系统是安卓吗,揭秘其与... 亲爱的读者,你是否曾好奇过,那些运行在我们手机上的操作系统,它们究竟是不是安卓呢?今天,就让我带你一...
安卓上跑windows系统,安... 你有没有想过,在安卓手机上也能体验到Windows系统的魅力呢?没错,这就是今天我要跟你分享的神奇故...
安卓系统自动下载应用,轻松享受... 你有没有发现,手机里的安卓系统有时候会自动下载一些应用,让你有点摸不着头脑呢?这到底是怎么回事呢?今...
安卓系统标志猪图标,揭秘安卓系... 你有没有注意到,安卓系统里那个标志性的猪图标?它可是安卓家族的吉祥物呢!今天,就让我带你来一探究竟,...
touchpad安卓9双系统,... 你有没有想过,你的手机触控板竟然也能玩转安卓9双系统?没错,就是那个我们平时用来滑动、点击的小玩意儿...
安卓系统10多个g,安卓系统1... 你有没有发现,最近你的安卓手机变得越来越“胖”了?没错,说的就是那个安卓系统,它竟然悄悄地膨胀到了1...
三星系统和安卓系统关系,深入解... 你有没有想过,为什么你的手机里装的是三星系统而不是苹果的iOS呢?这背后其实有着一段复杂的故事,三星...
安卓杂牌机刷鸿蒙系统,体验鸿蒙... 你有没有想过,那些在街头巷尾随处可见的安卓杂牌机,竟然也能焕发新生,变身成为鸿蒙系统的忠实拥趸呢?没...
安卓系统变成ios5,系统变革... 你知道吗?最近有个大新闻在科技圈里炸开了锅,那就是安卓系统竟然变成了iOS 5!是的,你没听错,就是...
如何给电脑转安卓系统,电脑变安... 你有没有想过,把你的电脑变成安卓系统,是不是瞬间觉得整个世界都变得不一样了呢?想象你可以在电脑上直接...
云系统安卓系统教程pdf下载地... 你有没有想过,手机里的安卓系统其实就像一个巨大的云系统,里面藏着无数的秘密和宝藏?今天,我就要带你一...
安卓系统同步没打开,揭秘同步设... 亲爱的手机控们,你是否也有过这样的烦恼:明明想要同步手机上的照片、联系人、日历等重要信息,却发现安卓...
安卓系统发热耗电快,安卓手机发... 手机这玩意儿,现在可是咱们生活中不可或缺的好伙伴。但是,你知道吗?有些安卓手机在使用过程中,总是会出...
安卓系统可执行的脚本,Andr... 你有没有想过,你的安卓手机里那些看似普通的APP,其实可能隐藏着强大的脚本执行能力呢?没错,就是那种...