博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,数据结构
座右铭:“不要等到什么都没有了,才下定决心去做”
大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点
目录
栈
栈的概念
顺序表和链表的优缺点
栈结构体的定义
栈的初始化
栈的销毁
入栈
出栈
栈顶元素
判断的栈是否为空
栈元素个数
栈的源码
main文件
test.h文件
test.h文件
栈的概念
顺序表和链表的优缺点
顺序表的缺点:
1.前面部分插入删除数据,效率是O(N),需要挪动数据。(物理空间是连续的)
2.空间不够,需要扩容。a.扩容是需要付出代价的,b.一般还会伴随空间浪费
顺序表的优点:
1.尾插尾删效率比较高
2.下标的随机访问
3.cpu高速缓存命中率较高
链表(带头双向循环链表)优点:
1.任意位置插入删除O(1)
2.按需申请释放空间
链表缺点:
不支持下标的随机访问
cpu高速缓存命中率较低
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中数据元素遵守后进先出(LIFO)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈,出数据也在栈顶
栈就是在线性表的基础上加以限制(遵循后进先出的原则)
例如:
入栈:1 2 3 4
出栈:4 3 2 1(入完4个数据在出数据)
1 2 3 4(入一个数据,出一个数据)
3 2 4 1(先入1 2 3,再出3 2,再入4,出 4 1)
...
注意: 3 1 4 2这种出栈的顺序是不可能的
实现栈有两种形式:
1.数组栈(顺序表)(尾做栈顶)
2.链表栈(链表)(用头做栈顶)
本文使用的就是第一种,用顺序表完成的栈
栈结构体的定义
1.a动态存储数据的数组 2.top栈有效元素的个数 3.capacity栈的容量
typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST;
栈的初始化
栈的初始化,这里是将栈元素的有效个数设置为0(pst->top=0),你也可以把它设置为-1,根据自己的要求设计
void STInit(ST* pst) { assert(pst); pst->a=NULL; // pst->top=-1;//指向栈顶数据 pst->top=0;//指向栈顶数据的下一个位置 pst->capacity=0; }
栈的销毁
由于是顺序表栈,只需要free头指针就行,将结构体元素全部置空
void STDestroy(ST* pst) { assert(pst); free(pst->a); pst->a=NULL; pst->top=pst->capacity=0; }
入栈
栈(顺序表)采用的是尾插法来完成入栈
void STPush(ST* pst,STDataType x) { assert(pst); if(pst->capacity==pst->top) { //如果栈容量为空则,则开辟四个空间,否则新开辟的空间是原来空间的两倍 int newCapacity=pst->capacity==0?4:pst->capacity*2; STDataType* temp=(STDataType *)realloc(pst->a,newCapacity*sizeof(STDataType)); if(temp==NULL) { perror("realloc fail"); return ; } pst->a=temp; pst->capacity=newCapacity; } pst->a[pst->top]=x; pst->top++; }
出栈
出栈就是将元素移除栈,这里采用了顺序表的尾删,直接将栈内有效个数(pst->top)减一
void STPop(ST* pst) { assert(pst); assert(!STEmpty(pst)); pst->top--; }
栈顶元素
返回栈顶的元素,这里注意一下,top是有效个数是从1开始记录的,但是顺序表的下表从0开始记录,所以我们这里pst->top-1
STDataType STTop(ST* pst) { assert(pst); assert(!STEmpty(pst)); return pst->a[pst->top-1]; }
判断的栈是否为空
判断栈内元素是否为空,如果为空返回true,否则返回false
bool STEmpty(ST* pst) { assert(pst); return pst->top==0; }
栈元素个数
判断栈元素的有效个数,并返回
int STSize(ST* pst) { assert(pst); return pst->top; }
栈的源码
main文件
#include "test.h" void test1(void) { ST s1; STInit(&s1); STPush(&s1, 1); STPush(&s1, 2); STPush(&s1, 3); STPush(&s1, 4); printf("total:%d\n",STSize(&s1)); while(!STEmpty(&s1)) { printf("%d ",STTop(&s1)); STPop(&s1); } } int main() { test1(); return 0; } //结果: //total:4 //4 3 2 1
test.h文件
#ifndef test_h #define test_h #include
#include #include #include #endif /* test_h */ typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST; //栈的初始化 void STInit(ST* pst); //栈的销毁 void STDestroy(ST* pst); //入栈 void STPush(ST* pst,STDataType x); //出栈 void STPop(ST* pst); //栈顶元素 STDataType STTop(ST* pst); //判断的栈是否为空 bool STEmpty(ST* pst); //栈元素个数 int STSize(ST* pst); test.h文件
#include "test.h" //栈的初始化,这里是将栈元素的有效个数设置为0(pst->top=0),你也可以把它设置为-1,根据自己的要求设计 void STInit(ST* pst) { assert(pst); pst->a=NULL; // pst->top=-1;//指向栈顶数据 pst->top=0;//指向栈顶数据的下一个位置 pst->capacity=0; } //由于是顺序表栈,只需要free头指针就行,将结构体元素全部置空 void STDestroy(ST* pst) { assert(pst); free(pst->a); pst->a=NULL; pst->top=pst->capacity=0; } //栈(顺序表)采用的是尾插法来完成入栈 void STPush(ST* pst,STDataType x) { assert(pst); if(pst->capacity==pst->top) { //如果栈容量为空则,则开辟四个空间,否则新开辟的空间是原来空间的两倍 int newCapacity=pst->capacity==0?4:pst->capacity*2; STDataType* temp=(STDataType *)realloc(pst->a,newCapacity*sizeof(STDataType)); if(temp==NULL) { perror("realloc fail"); return ; } pst->a=temp; pst->capacity=newCapacity; } pst->a[pst->top]=x; pst->top++; } //出栈就是将元素移除栈,这里采用了顺序表的尾删,直接将栈内有效个数(pst->top)减一 void STPop(ST* pst) { assert(pst); assert(!STEmpty(pst)); pst->top--; } //返回栈顶的元素,这里注意一下,top是有效个数是从1开始记录的,但是顺序表的下表从0开始记录,所以我们这里pst->top-1 STDataType STTop(ST* pst) { assert(pst); assert(!STEmpty(pst)); return pst->a[pst->top-1]; } //判断栈内元素是否为空,如果为空返回true,否则返回false bool STEmpty(ST* pst) { assert(pst); return pst->top==0; } //判断栈元素的有效个数,并返回 int STSize(ST* pst) { assert(pst); return pst->top; }
如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家!