❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀
♪♪♪ 若有转载,请联系博主哦~ ♪♪♪
❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤
铁汁们,我又回来了,不知道大家有没有想我呢?哈哈,大伟现在的学校的课是真的很多啊,完全不能和上学期相比,之后的周一和周五基本都没有时间来更新博客了,希望大家理解哈~╮(╯▽╰)╭更何况这一周是第一周,实在是有给大伟累到,所以本次的博客:栈,就会相对简单也更短一些了,不过大家也不要停止学习啊(╯ε╰)
之前的数据结构我们谈论了链表的两种:单链表和双向链表,不知道大家有没有理解呢?不过数据结构对于我们这种新手来说确实难了一点,但是大伟相信,只要我们付出相对应的时间,我们终有一天会变成大牛的!(ง •_•)ง
好的,话不多说了,我们开始今天的学习吧:栈。
那么在写代码之前,我们先来了解一下数据结构里面的栈是什么:
在计算机科学中,栈(Stack)是一种数据结构,它遵循先进后出(Last In, First Out,LIFO)的原则。这意味着最后进入栈的元素是第一个被取出的,而最先进入栈的元素是最后被取出的。栈可以看作是一种容器,只能在容器的一端(称为栈顶)进行插入和删除操作,另一端(称为栈底)是固定的。
栈有两个主要的基本操作:
- 压入(Push):将元素添加到栈顶。
- 弹出(Pop):从栈顶移除元素。
如上,我们知道了栈是遵循LIFO的原理的,那我们该如何实现呢?我们有两个思想:
- 联想之前的链表,用链表的结构实现栈
- 不知道大家还记不记得,我们一开始在学习单链表的时候,当时也有两个备选方案:1.就是我们现在沿用的一次开一个空间的方法 2.是定义一个定长的数组,然后再进行扩容,没错,就是顺序表
那我们该用那种呢,我们来分析一下:
如果我们选用链表的方法,每次压入元素就创建一个空间(节点),每次删除元素就释放一个空间,而为了释放尾节点的空间,我们是不是就需要一个tail(尾节点)的指针,而且需要一个prev来链接两个空间,综上,我们该使用哪种链表? 没错,就是双向链表,然后我们再思考其他的方面是不是也觉得没问题?好,就觉得是你了,双向链表!
诶,等等,别这么猴急啊~ (~ ̄▽ ̄)~ ,不知道大家有没有觉得就为了实现一个尾部的增添而选用双向链表太浪费(麻烦)了? 于是我们再来分析一下数组的方法:
如果我们选用数组的方法,假如我们初始给了四个空间,我们就会需要一个top节点来记录数组存放最后一个有效数据的坐标,一个capacity来记录当前数组的总大小,如果要压入元素就直接在当前的top的下一个下标位置放入元素,如果要弹出元素就直接top减一(当然前提是空间足够)
诶,这样一对比无论是从思维还是从代码量方面都是选择数组更好一点,那么,开码吧!
老规矩:Stack.c Stack.h test.c
Stack.h
cpp
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; // 栈顶
int capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
Stack.c
初始化:
cpp
void StackInit(Stack* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
压入:
cpp
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
if (ps->capacity == ps->top)
{
//扩容
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->a,newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("malloc fail");
return;
}
ps->a = tmp;
ps->capacity = newcapacity;
}
//给值
ps->a[ps->top++] = data;
}
弹出:
cpp
void StackPop(Stack* ps)
{
assert(ps);
//若栈为空
assert(!StackEmpty(ps));
//不需要改变值,因为已经没用了
ps->top--;
}
判断栈是否为空:
cpp
int StackEmpty(Stack* ps)
{
assert(ps);
//若top为0,则返回true,否则返回false
return ps->top == 0;
}
取栈顶元素:
cpp
STDataType StackTop(Stack* ps)
{
assert(ps);
//若栈为空
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
栈的大小:
cpp
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
摧毁栈
cpp
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
解决了,是不是很简单?诶,先别着急,玩一玩?٩(͡๏̯͡๏)۶
test.c
cpp
int main()
{
Stack s;
StackInit(&s);
StackPush(&s, 1);//1
StackPush(&s, 2);//1 2
int top = StackTop(&s);//top = 2
printf("%d ", top);//2
StackPop(&s);//1
StackPush(&s, 3);//1 3
top = StackTop(&s);//3
printf("%d ", top);//3
StackPop(&s);//1
top = StackTop(&s);//1
printf("%d ", top);//1
return 0;
}
可以看到,我们的代码是没有什么问题龙图,如果大家还有别的想要测试的话,自己私下实现哦~
到这里本篇博客已经可以是完结了,但是接着栈后面就是队列了,下篇文章我会对大家介绍,请大家继续支持大伟,谢啦!!☆⌒(*^-゜)v
A bird in the hand is worth two in the bush. 双鸟在林不如一鸟在手。
本篇博客也就到此为止了,送大家一碗鸡汤,勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己,莫欺少年穷!