目录
栈的定义
栈(Stack) :相对于顺序表来说,栈是一种只允许在一端进行插入或者删除操作的线性表。
在生活中我们的很多东西类似于栈的操作,就比如这一堆盘子,摞起来就是一个栈,当你想放一个盘子的时候,你只能放在顶部,或者当你想拿走一个盘子的时候,你只能从上面依次拿走。这里大家可以想象一下!
栈的类型
栈分为顺序栈和链栈
顺序栈
顺序栈:用顺序存储的方式实现的栈,在物理结构上是连续的。顺序栈和顺序表类似,不过栈只能在一端进行插入或者删除操作。
链栈
链栈:用链式存储的方式实现的栈,在物理结构上是不连续的。链栈和链表也是类似,不过栈只能在一端进行插入或者删除操作。
栈相关术语
空栈
当栈里面没有数据元素的时候,里面就是空的,这个大家应该可以想到,这是的栈就是空栈。
栈顶和栈底
在上文中,我们提到了栈这种数据结构只能在一端插入或者删除数据,那么插入或者删除的一端叫做栈顶,正如下图所示。栈底这里就不做过多的介绍了。
栈的特点
先进后出(LIFO):Last In First Out,这里给大家画图再解释一下子。
空栈的时候,从栈顶插入一个数据A,然后这个时候我们也可以选择继续插入数据B,或者删除数据A,在这里我们把插入数据叫做入栈,删除数据元素叫做出栈,在后续的内容中,我们就是用入栈和出栈来表示插入或者删除数据了。
这里是个考点,大家注意一下哈。
栈的基本操作(顺序栈)
这里我们以静态顺序栈为先例
我们定义一个Stack.c的文件用来实现函数操作,用Stack.h文件用来存放函数的声明和存放结构体,用test.c文件来实现栈的基本操作。
#define MaxSize 10 //定义栈的最大容量
typedef int Elemtype;
typedef struct Stack {
Elemtype data[MaxSize]; //用静态的“数组”存放数据元素
int length; //用来记录当前的栈的长度
}Stack;
初始化
void InitStack(Stack* S)
{
S->length = 0; //这里的话,其实也可以初始化为-1,不过后面的操作会有些变化,大家可以尝试一下子
memset(S->data, 0, sizeof(Elemtype) * MaxSize);
}
这里我们可以用memset()这个库函数来实现对顺序栈的初始化,在这里使用memset()这个库函数要记得包含头文件。
这里小编给大家讲解一下memset()这个库函数
void * memset ( void * ptr, int value, size_t num );
第一个参数是要初始化数组的首地址,第二个参数是要初始化的内容,第三个参数是要初始化的大小(单位是字节)
这里小编带大家调试一下
void InitStack(Stack* S)
{
S->length = 0;
for (int i = 0; i < MaxSize; i++)
{
S->data[i] = 0;
}
}
或者我们也可以用循环的方式来实现对顺序栈的初始化,这里大家可以自行选择。
入栈
刚开始的时候是空栈,栈顶指针和栈底指针指向同一块位置。
void Push(Stack* S, Elemtype x)
{
if (S->length == MaxSize)
{
return;
}
S->data[S->length] = x;//这里的话也可以写成这样S->data[S->lengh++]=x
S->length++;
}
这里跟大家解释一下,为什么是 data [length] = x,刚开始的时候,栈的长度是0,然后数组的下标是从0开始的对吧,当你存入第一个数据的时候,这时候表的长度就是1了,然后数组下标为1的位置这时候还没有数据,就相当于每次存入的数据是在length这个指针的前面,当length指向MaxSize的时候,这时候栈的长度刚好是10,这里大家可以想象一下。
if (S->length == MaxSize)
{
return;
}
这里的if语句用来判断栈是否存满了。
出栈
上面我们说到入栈实在Length指针的前一个下标入栈的,现在我们要出栈的话,只需要将Length向前移动一下,这里大家可以思考一下。
void Pop(Stack* S)
{
if (S->length < 0) //当栈为空的时候
{
return;
}
S->length--;
}
返回栈顶元素
int Top(Stack* S)
{
return S->data[S->length - 1];
}
这里解释一下,为什么-1,因为上文中也提及过,每次入栈之后,length就指向下一个位置了。
判空
bool Empty(Stack* S)
{
return S->length == 0;
}
总结
函数声明:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#define MaxSize 10 //定义栈的最大容量
typedef int Elemtype;
typedef struct Stack {
Elemtype data[MaxSize]; //用静态的“数组”存放数据元素
int length; //用来记录当前的栈的长度
}Stack;
void InitStack(Stack* S);
void Push(Stack* S, Elemtype x);
void Print(Stack* S);//可以用这种打印
void Pop(Stack* S);
bool Empty(Stack* S);
int Top(Stack* S);
函数体:
#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
void InitStack(Stack* S)
{
S->length = 0;
memset(S->data, 0, sizeof(Elemtype) * MaxSize);
}
void Push(Stack* S, Elemtype x)
{
if (S->length == MaxSize)
{
return;
}
S->data[S->length] = x;
S->length++;
}
void Print(Stack S)
{
for (int i = 0; i < S.length; i++)
{
printf("%d ", S.data[i]);
}
printf("\n");
}
void Pop(Stack* S)
{
if (S->length < 0) //当栈为空的时候
{
return;
}
S->length--;
}
bool Empty(Stack* S)
{
return S->length == 0;
}
int Top(Stack* S)
{
return S->data[S->length - 1];
}
函数实现:
#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
void test()
{
Stack S; //声明栈
InitStack(&S);//初始化栈
Push(&S, 1);
Push(&S, 2);
Push(&S, 3);
Push(&S, 4);
Push(&S, 5);
Push(&S, 6);
Push(&S, 7);
Push(&S, 8);
Push(&S, 9);
Push(&S, 10);
//Print(S);
Pop(&S);
Pop(&S);
Pop(&S);
Pop(&S);
while (!Empty(&S))//也可以用这种
{
printf("%d ", Top(&S));
Pop(&S);
}
//Print(S);
}
int main()
{
test();
return 0;
}
制作不易,如有问题,大家可以随时向小编反应,大家一起共同进步。
最后在这里,小编提前祝大家新春快乐!!!