【神秘海域】「附代码」数据结构:栈 详解

Stack_Cover


引言

数据结构中有 四大基础结构 ,即 四大线性表:顺序表、链表、、队列

被称为线性表是因为,数据用以上四种结构存储,在逻辑结构上都是 在一条线上相邻连续的

线性结构逻辑结构图示:
顺序表
链表
队列

前面已经介绍了前两个:顺序表链表

本篇文章就来介绍一下 这种数据结构。

什么是栈

前几篇文章介绍的 顺序表链表 都属于比较自由的数据结构,没有限制存入数据应该从哪里存入

但是, 就不一样了

规定 只能从固定的一端 入数据(存放数据)出数据(删除数据),并称这一端为 栈顶。另一端称为 栈底

入数据(存放数据) 的操作,通常被称作:压栈

出数据(删除数据) 的操作,通常被称为:出栈

也就是说,压栈出栈 都是从 栈顶 进行操作的

数据结构中的 与 操作系统中的 ,本质上是完全不同的,相同的 只有 名字创建销毁(出入数据)顺序

操作系统中的 ,如果调用函数,创建栈帧是从栈顶创建的,销毁栈帧也是从栈顶销毁的

详情可阅读博主本篇文章:【程序员的自我修养】[动态图文] 超详解函数栈帧

存放数据的方式就像 砌砖,在 不破坏结构 的情况下只能这样 放 和 拿:

由图 可以看出 是一种 后进先出(LIFO) 的数据结构,即 最后放入的数据,最先出来

基于这种 只能从栈顶存入删除数据,后进先出 的规则, 结构的实现一般由 数组 来实现

当然也可以用 链表 进行实现,不过 用单链表的话,想要效率只能 头插 头删, 不便于理解;更复杂的链表的话,会有多出的节点什么的也不方便。所以最好还是 用数组实现栈

以下 栈 也由 数组 实现

栈的结构

指定了 只能从栈顶进行 压栈出栈 的操作。所以结构内,除数组之外,还需要记录栈顶位置的变量

所以 结构一般为:

typedef int StackDataType;

typedef struct Stack
{
	StackDataType *data;
	int Top;				//记录栈顶位置
	int Capacity;			//记录数组容量
}Stack;

这里注意:

Top(记录栈顶位置) 变量的初值一般有两种情况:-10

Top 初值不同,接口的实现 会有细微的差异:
初值为 -1Top 指向数组最后一个元素的位置;压栈时,Top 先加一,再入数据

image-20220507160801719

初值为 0Top 指向数组最后一个元素的下一位置;压栈时,先入数据,Top 再加一

image-20220507160745124

并且,由于 Top 有不同的情况,与栈有关的操作最好使用已有接口进行

栈的接口及实现

栈的常用接口

由于 规定了 入栈出栈 的位置,所以只有固定的 压栈出栈 操作,不支持其他位置的插入

所以 的接口一般有:

  1. 初始化 StackInit
  2. 入栈 StackPush
  3. 出栈 StackPop
  4. 取栈顶元素 StackTop
  5. 栈元素个数 StackSize
  6. 判空 StackEmpty
  7. 栈销毁 StackDestroy

初始化 StackInit

Top 初始化有两种情况,这里选择 初始化为 0

void StackInit(Stack *pst)
{
	assert(pst);
	
	pst->data = NULL;
	pst->Top = pst->Capacity = 0;
}

image-20220507173412153

入栈 StackPush

因为只有 压栈 时,栈的容量可能会满,所以就不需要单独写一个判断栈满的函数了

void StackPush(Stack *pst, StackDataType x)
{
	assert(pst);

	if (pst->Top == pst->Capacity)		// 数组已满	扩容
	{
		int newCapacity = pst->Capacity == 0 ? 4 : pst->Capacity * 2;
		StackDataType *tmp = (StackDataType*)realloc(pst->data, sizeof(StackDataType)* newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		pst->data = tmp;
		pst->Capacity = newCapacity;
	}

	pst->data[pst->Top++] = x;
    /*	Top 初值为 -1
    psy->data[++pst->Top] = x;
    */
}

image-20220507174850928

出栈 StackPop

因为 由 数组 实现的栈,开辟的空间是 不能单独释放 的。即:出栈,不需要释放空间,也不需要修改数据

所以 出栈 非常的简单!!

void StackPop(Stack *pst)
{
	assert(pst);
	assert(pst->Top > 0);		//保证栈不为空
	/*	Top 初值为 -1
	assert(pst->Top > -1);
	*/

	--pst->Top;
}

因为,在 中是由 Top 来决定 存放数据的数量的,所以 Top 减小就代表 有数据出栈

取栈顶元素 StackTop

// 取栈顶元素
StackDataType StackTop(const Stack *pst)
{
	assert(pst);
	assert(pst->Top > 0);	

	return pst->data[pst->Top - 1];
	/*	Top 初值为 -1
	return pst->data[pst->Top];
	*/
}

image-20220507181738115

判空 StackEmpty

// 判空
bool StackEmpty(const Stack *pst)
{
	assert(pst);

	return pst->Top == 0;
	/*	Top 初值为 -1
	return pst->Top == -1;
	*/
}

image-20220507182200048

栈元素个数 StackSize

int StackSize(const Stack *pst)
{
	assert(pst);

	return pst->Top;
	/*	Top 初值为 -1
	return pst->Top + 1;
	*/
}

image-20220507182706721

栈销毁 StackDestroy

void StackDestory(Stack *pst)
{
	assert(pst);

	free(pst->data);
	pst->data = NULL;
	pst->Capacity = pst->Top = 0;
}

image-20220507183021201


至此, 的结构以及常用接口的 分析与实现 都已经完成了。

栈结构及接口 是非常简单的,但是关于 的题可能会很麻烦(因为后进先出)

结语

本篇文章 对 数据结构:栈 结构及接口 进行了 分析和实现。

但只是 由 数组实现的栈,有兴趣可以 用链表实现栈

OK~ 本篇文章到此结束~


求点赞、评论、收藏~

给你点个赞

  • 56
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 77
    评论
评论 77
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七月.cc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值