1.栈的定义:
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/入栈,插入数据是在栈顶操作;
出栈:栈的删除操作叫做出栈,出数据也在栈顶;
1.2栈的特性:
先进后出
栈的最经典的特性就是先进后出,也可以被叫做后进先出;
这怎么理解呢,就相当于是枪的弹夹,在填装子弹的时候和取出子弹的时候,我们会发现最先放进去的子弹反而是被最后取出的,而最后放入的子弹是最先放进去的;
1.3栈的实现:
分析:对于栈的实现来说,我们有两种数据结构可待选择;
一种是链表,一种是数组;
对于栈的话我们要进行的最多的就是出栈和入栈的操作了。
首先我们来讲数组:数组对于实现入栈出战来说还是很方便的,特别是选用尾部为栈顶的话。只需要的就是数组的扩容问题,只需要调用realloc函数即可。
再其次是链表:对于链表的话我们如果选用单链表的话,若是选用尾部为栈顶的话,我们就很麻烦,每次都需要遍历找到链表的尾指针;
而且相对来说数组的尾插和尾删的效率都很高。
所以这里我们选择先使用数组来实现栈;
1.4代码:
1.4.1结构的声明:
首先我们来分析对于一个用数组来实现的栈来说,我们只需要有一个数组指针,标记栈顶位置的变量,和一个记录栈的容量的变量;
typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST;
1.4.2栈的初始化:
void StackInit(ST* ps);这个函数我们实现的是对于栈的初始化,这个函数的参数是一个结构体类型的指针,我们只需要将结构体内部包含的一个数组指针置空,和两个分别表示栈顶位置的变量和栈的容量的变量都置成零即可。
这里有一个要注意的点就是我们把top也置为0,就是表示top每次指向的是栈顶的后一个位置;(这一点很重要后面的出栈和入栈都会用到)
代码:
//栈的初始化 void StackInit(ST* ps) { assert(ps); ps->a = NULL; ps->top = 0; ps->capacity = 0; }
1.4.3入栈:
void StackPush(ST* ps, STDataType x);
这个函数来试下入栈的操作,对于入栈来说我们最需要注意的就是空间问题,因为数组的大小是给固定的所以我们要在每次入栈的时候要进行一次判断,判断是否需要扩容,并且这里要注意的是top指的是栈顶的后一个位置,所以我们执行的是先插入数据后,再将top++的;
代码:
//入栈 void StackPush(ST* ps, STDataType x) { assert(ps); if (ps->top == ps->capacity) { int newCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2); STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity); if (tmp == NULL) { printf("realloc fail\n"); exit(-1); } ps->a = tmp; ps->capacity = newCapacity; } ps->a[ps->top] = x; ps->top++; }
1.4.4出栈
void StackPop(ST* ps);
对于数组实现的栈来说,出栈的操作非常简单,我们只需要将记录栈顶的位置的变量top--即可。
代码:
//出栈 void StackPop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); ps->top--; }
1.4.5拿到栈顶的数据
STDataType StackTop(ST* ps);这个函数实现的就是返回栈顶的数据,只需要将数组中对应栈顶的数据返回即可,这里需要注意的就是,在返回栈顶数据的时候数组的下标用的是top-1;
代码:
//拿到栈顶的数据 STDataType StackTop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); return ps->a[ps->top - 1]; }
1.4.6栈的大小
int StackSize(ST* ps);
这个函数返回的是栈的大小,只需要将top返回即可;
代码:
//栈的大小 int StackSize(ST* ps) { assert(ps); return ps->top; }
1.4.7判断栈是否为空
bool StackEmpty(ST* ps);如果栈的空间是空,我们就返回假,如果栈的空间是不为空,就返回真;
代码:
//栈是否为空 bool StackEmpty(ST* ps) { assert(ps); return ps->top == 0; }
1.4.8栈的销毁
void StackDestroy(ST* ps);
将数组指针置空,然后其他变量置为0即可;
代码:
//栈的销毁 void StackDestroy(ST* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = 0; ps->top = 0; }
以上就是栈用数组的实现了!
这里再推荐一个用到栈的力扣题大家可以去试一试练练手:
2.完整代码
源文件:
#define _CRT_SECURE_NO_WARNINGS 1 #include"stack.h" //栈的初始化 void StackInit(ST* ps) { assert(ps); ps->a = NULL; ps->top = 0; ps->capacity = 0; } //入栈 void StackPush(ST* ps, STDataType x) { assert(ps); if (ps->top == ps->capacity) { int newCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2); STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity); if (tmp == NULL) { printf("realloc fail\n"); exit(-1); } ps->a = tmp; ps->capacity = newCapacity; } ps->a[ps->top] = x; ps->top++; } //栈的销毁 void StackDestroy(ST* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = 0; ps->top = 0; } //出栈 void StackPop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); ps->top--; } //拿到栈顶的数据 STDataType StackTop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); return ps->a[ps->top - 1]; } //栈的大小 int StackSize(ST* ps) { assert(ps); return ps->top; } //栈是否为空 bool StackEmpty(ST* ps) { assert(ps); return ps->top == 0; }
头文件
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST; //栈的初始化 void StackInit(ST* ps); //栈的销毁 void StackDestroy(ST* ps); //入栈 void StackPush(ST* ps, STDataType x); //出栈 void StackPop(ST* ps); //拿到栈顶的数据 STDataType StackTop(ST* ps); //栈的大小 int StackSize(ST* ps); //栈是否为空 bool StackEmpty(ST* ps);
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"stack.h" void Teststack() { ST st; StackInit(&st); StackPush(&st, 1); StackPush(&st, 2); StackPush(&st, 3); StackPush(&st, 4); while (!StackEmpty(&st)) { printf("%d ", StackTop(&st)); StackPop(&st); } StackDestroy(&st); } int main() { Teststack(); return 0; }
以上就是本篇博客的所有内容了,如果帮到你请点赞关注收藏一下!