数据结构——栈(保姆级教程)

目录

栈的定义

栈的类型

顺序栈

链栈

栈相关术语

空栈

栈顶和栈底

栈的特点

栈的基本操作

初始化

入栈

出栈

返回栈顶元素

判空

总结:


栈的定义

(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;
}

制作不易,如有问题,大家可以随时向小编反应,大家一起共同进步。

最后在这里,小编提前祝大家新春快乐!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值