主页:114514的代码大冒险
qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ )
【声明】本文会出现一些其他数据结构的名称及相关名词,如果不了解相关数据结构自行忽略相应内容即可,本文在创建时秉承着联动其他数据结构的同时,又不影响初学数据结构的朋友能够完成文章主题内容的学习
引入
栈是一种线性表(如果不懂线性表,可以暂时将其理解为数组),但这不是普通的线性表,数据只能从固定一端进入,并在这一端拿出,这一端我们称之为栈顶,而另一端则为栈底
数据存取遵循后进先出(LIFO - Last In First Out) ,类似于在烧杯中放置与其口径略小的木块:
入栈---也叫压栈(存入数据于栈栈中):
出栈---退栈(从栈中取出数据):
类似的在生活中还有子弹夹(先安装的子弹靠后发射),刷洗盘子时,依次把每个洗净的盘子放到洗好的盘子上
于是乎,我们这篇文章主要来讲解如何用【c语言】搭建一个栈
分为 <栈-相关接口总览>
栈-分类
栈是一种特殊的线性表:
(这部分如果没有对顺序表和链表的学习,可以自行略过,不会影响下文的学习)
由上图可知,栈可以是个特殊的链表,也可以是个特殊的顺序表
如果是个链表:
【解释】链表的尾删每次都需遍历整个链表,效率太低,所以我们选择表头作为栈顶
如果是个顺序表:
【解释】顺序表的尾删效率要比头删(把除头位置以外的数据向前挪动一个单位)高,所以我们选择以表尾作栈顶
【比较】两种实现都差不多,但是相比较而言顺序表的形式更优一点,因为链表的每一个节点都需要单独申请动态内存,多次申请产生较多的内存碎片,消耗也大一些,而顺序表则在这方面优于链表
栈-相关接口总览
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);//判断栈是否为空
(接口就是函数)
栈-具体接口实现(以顺序表的形式)
我们用top表示栈顶位置的下一个
capacity表示栈的总容量
类似下图这般:
初始化
void StackInit(ST* ps) { assert(ps); ps->a = NULL; ps->top = 0; ps->capacity = 0; }
销毁
void StackDestroy(ST* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = ps->top = 0; }
压栈
void StackPush(ST* ps,STDataType x) { assert(ps); if(ps->top == ps->capacity) { int newCapacity = ps->capacity == 0 ? 4:ps->capacity* 2; //三目操作符,如果容量为0,我们将将其变为4,不为零,则将容量二倍 STDataType* tmp = realloc(ps->a,size0f(STDataType)*newCapacity); if(tmp == NULL) { printf("realloc fail\n"); exit(-1);//申请内存失败,退出程序 } ps->a[ps->top] = x;//栈顶存放数据 ps->top++;//使top再次指向栈顶的下一个位置 } }
出栈
void StackPop(ST* ps) { assert(ps); assert(ps->top > 0); ps->top--;//top表示栈顶的下一个位置,top往后退一个单位 //栈顶也往后退一个单位 }
取出栈顶数据
STDataType StackTop(ST* ps) { assert(ps); assert(ps->top > 0); return ps->a[ps->top - 1]; }
判断栈是否为空
bool StackEmpty*(ST* ps) { assert(ps); // if(ps->top > 0) // { // return ture; // } // else // { // return false; // } // 被注释掉的是另一种实现该接口的逻辑 return ps->top == 0; // 我们选择简单一点,直接执行一个判断语句,返回判断语句的结果 }
总文件
头文件
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);
接口文件
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 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,size0f(STDataType)*newCapacity);
if(tmp == NULL)
{
printf("fealloc fail\n");
exit(-1);
}
ps->a[ps->top] = x;
ps->top++;
}
}
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
STDataType StackTop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int StackSize(ST* ps)
{
}
bool StackEmpty*(ST* ps)
{
assert(ps);
// if(ps->top > 0)
// {
// return ture;
// }
// else
// {
// return false;
// }
return ps->top == 0;
}
写在最后
我真诚的希望你能够阅读本文时,得到一些帮助与启发
这是我第一次尝试省去每段接口的单独思路分析,而是直接对代码进行较为详细的注释
文中当然还存在各种各样的不足,欢迎私信告诉我,
同时,我知道我的表达水平有限,语言也还不够通俗易懂,所以我随时欢迎你的私信
我是真的掌握了这部分的内容才将它写出来,所以,有任何疑问,call me!!