【数据结构】简单到有摸鱼负罪感的栈的实现

news2024/10/7 4:32:58

【数据结构】简单到有摸鱼负罪感的栈的实现

  • 一、前言
    • 1、什么是栈?
    • 2、关于实现的结构选取
  • 二、目标
  • 三、实现
    • 1、初始化工作
    • 2、压栈(push)
      • 2.1、图解思路
      • 2.2、代码实现
    • 3、弹栈(pop)
      • 3.1、图解思路
      • 3.2、代码实现
    • 4、打印栈(用于测试)
    • 5、返回栈顶数据
    • 6、返回栈的数据个数
    • 7、判断栈是否为空
    • 8、销毁栈

一、前言

1、什么是栈?

对于栈,百度百科上对它的介绍是这样的:

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
在这里插入图片描述
——————————————————————引自百度百科

其实我们可以形象的把栈比喻成一个子弹夹:
在这里插入图片描述
士兵在压入子弹的时候是从顶端压入,子弹出膛的的时候也是从顶端出,典型的后进先出结构。

栈这种结构其实在我们的计算机中也有很多的应用,最典型的就是我们函数栈帧:
在这里插入图片描述
我们在调用函数的时候会一次在栈顶形成栈帧,在函数调用结束时候也是从顶往下销毁栈帧,也是遵循了后进先出的规则。

经过上面的介绍大家会发现栈的结构比起其他的结构好像要简单很多。而实事也正是如此,因为栈的规定就是只能在栈顶入数据和出数据,所以我们实现的时候后最主要要实现的功能就两个:压栈(push)和弹栈(pop)。
接下来就让我们来实现这个简单的栈结构吧。

2、关于实现的结构选取

因为栈也是一个顺序结构,所以原则上只要是顺序结构就都能用来实现栈,比如说数组、链表、顺序表、队列……:
在这里插入图片描述
而其中实现最简单的就是数数组栈了,因为数组尾部数据的插入和删除都是很简单的,所以我们只需要将数组尾部设计成栈顶即可。
而链表栈,因为链表的尾删复杂度是O(n),所以我们可以将链表的头设计成栈顶,这样的话压栈和弹栈就对应的是头插和头删,我们直接点用相应的接口即可。
但队列栈的实现就要复杂得多了,实际上要用到两个队列,具体实现可以参考[LeetCode 225. 用队列实现栈]。

而我们今天既然是简单到像摸鱼的栈实现,当然选用的是最简单的数组实现栈啦。

二、目标

关于栈,我们要实现的主要功能如下:

// 栈的初始化
void StackInit(Stack* ps);
// 压栈
void StackPush(Stack* ps, DataType x);
// 弹栈
void StackPop(Stack* ps);
// 栈的打印(用于测试)
void printStack(Stack* ps);
// 返回栈顶数据
DataType StackTop(Stack* ps);
// 返回栈的数据个数
int StackSize(Stack* ps);
// 判断栈是否为空
bool StackEmpty(Stack* ps);
// 栈的销毁
void DestroyStack(Stack* ps);

三、实现

1、初始化工作

同样的我们还是先要将相应的结构定义一下:

// 重定义数据类型
typedef int DataType;

// 定义栈结构
typedef struct stack {
	DataType* data; // 数组指针
	int top; // 栈顶指针
	int capacity; // 栈的容量
} Stack;

然后我们要将栈给初始化一下,先将栈中的数组给置空,并将top和capacity都置成0:

// 栈的初始化
void StackInit(Stack* ps) {
	assert(ps);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

其实这里的top的初始化可以选择两种方案,一种是初始化成0一种是初始化成-1。
如果初始化成0的话就表示top始终指向的是栈顶元素的上一个元素(未入栈):
在这里插入图片描述
如果选择初始化成0,那我们在实现的时候就要注意先压入数据后再让top向上走,如果选择初始化成-1就要先让top往上走在压入数据。

初始化工作完成后,我们就可以来实现各个功能了。

2、压栈(push)

2.1、图解思路

既然我们选择了最简单的数组来实现栈,那压栈就很简单了,只需要将数组对应的位置赋上新的值即可:
在这里插入图片描述
最后再让top向上走一步:
在这里插入图片描述
而当我们不断地压入数据,原先开辟出来的栈空间有可能满,所以我们在压入数据之前要先检查一下栈是否满了,如果满了就要进行扩容。
扩容我们使用realloc函数就行。如果原来的栈的容量是空,那我们就先将栈的容量初始化为10,以后再以两倍的容量进行扩容。

2.2、代码实现

// 压栈
void StackPush(Stack* ps, DataType x) {
	assert(ps);
	// 检查是否需要增容
	if (ps->top == ps->capacity) {
		int newCapacity = ps->capacity == 0 ? 10 : ps->capacity * 2;
		DataType* temp = (DataType*)realloc(ps->data, newCapacity * sizeof(DataType));
		if (NULL == temp) {
			perror("ralloc fail!\n");
			exit(-1);
		}
		ps->data = temp;
		ps->capacity = newCapacity;
	}
	ps->data[ps->top] = x;
	ps->top++;
}

3、弹栈(pop)

3.1、图解思路

因为我们栈中能访问到的元素是通过top来控制的,所以我们在弹栈的时候并不需要将原来栈顶的数据给删除掉,只需要让top–即可:
在这里插入图片描述
因为我们后面在压入数据的时候,新的数据就会将原来的数据给覆盖掉,所以我们删不删除原来的数据都是一样的。
但我们同时还要对栈进行判空,栈为空的时候就不能再弹栈了。

3.2、代码实现

// 弹栈
void StackPop(Stack* ps) {
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

4、打印栈(用于测试)

其实在标准库中的栈其实没有打印这个功能的,这里实现的打印其实是为了用于更好地测试。
为了符合栈的结构,所以我们在打印的时候需要从栈顶开始打印:

// 栈的打印
void printStack(Stack* ps) {
	assert(ps);
	int i = 0;
	for (i = ps->top - 1; i >= 0; i--) {
		printf("[%d]\n", ps->data[i]);
	}
}

而又因为我们选择的是让top指向栈顶元素的上一个元素,所以我们这里要将i初始化成top - 1。
有了打印函数,我们就可以来测试以下上面上面所写的push和pop了,
我们先压入几个数据:
在这里插入图片描述
我们可以看到先压入的数据在底下,后压入的数据在上面,所以我们写的push是没有问题的。
我们再来弹栈试试:
在这里插入图片描述
结果显示确实是从栈顶弹出数据,所以我们写的pop也是没有问题的。

5、返回栈顶数据

这个其实就不用多说了,当栈不为空的时候返回栈顶数据即可:

// 返回栈顶数据
DataType StackTop(Stack* ps) {
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->data[ps->top - 1];
}

同样的我们这里要返回的其实是top - 1所指向的数据。

6、返回栈的数据个数

对于栈中的数据个数,因为数组的下标是从0开始的,而top指向的又是栈顶元素的上一个元素,所以我们直接返回top即可:

// 返回栈的数据个数
int StackSize(Stack* ps) {
	assert(ps);
	assert(ps->top >= 0);
	return ps->top;
}

7、判断栈是否为空

当top为0的时候就表示栈为空,所以我们直接返回top是否等于0的判断结果就行:

// 判断栈是否为空
bool StackEmpty(Stack* ps) {
	assert(ps);
	return ps->top == 0;
}

8、销毁栈

因为数组是用realloc函数在堆中动态开辟的一块连续的空间,所以我们直接用free函数释放掉整个数据即可,然后再将top和capacity都置成0:

// 栈的销毁
void DestroyStack(Stack* ps) {
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

源码环境搭建-唯一客服系统文档中心

运行源码环境 golang语言为跨平台的开发语言,使用唯一客服系统全源码版本,进行二次开发,需要搭建golang运行环境,并且开启go module依赖管理 Windows系统 首先下载golang压缩包,在下面这个地址下载https://studygolang…

第六章:空间解析几何-空间向量

1.空间向量 1.知识概述 1.理解向量的概念和几何表示2.掌握向量的加减法运算3.能够在三维空间内解决常见的向量问题2.向量 1.定义:(在空间内),既有大小又有方向的量叫做(空间)向量。2.表示法:向量可用有向线段表示,有向线段的长度表示向量的大小,有向线段的方向表示向…

网关zuul的使用

前言 Spring Cloud Zuul 主要的功能是提供负载均衡、反向代理、权限认证、动态路由、监控、弹性、安全等的边缘服务。其主要作用是为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备…

Matlab 迭代法(2)高斯牛顿法

一、思想 高斯牛顿法的对象是最小二乘法。 采用一定的方法对Hession 矩阵进行近似,这样的话可以减少计算量,只需要计算一阶偏导数得到雅可比矩阵即可。 minF(x)|| f(x)||^2 那么x在xk处的增量Δxk出的最小二乘法为 minF(xkΔxk)∣∣f(xk​Δxk​)∣…

10. 100ASK_V853-PRO开发板支持录音和播放音频

0.前言 ​ 本章主要讲述如何使用板载的MIC拾音咪头录音并使用喇叭播放音频。 ​ 音频_开发指南:https://tina.100ask.net/SdkModule/Linux_AudioFrequency_DevelopmentGuide-02/#220-v853 ​ 全志官方音频介绍:https://v853.docs.aw-ol.com/soft/tina…

HBase分布式安装配置

本环节需要使用root用户完成相关配置,安装HBase需要配置前置环境。命令中要求使用绝对路径,具体要求如下: 确认是否完成Hadoop和Zookeeper的分布式(Hadoop伪分布式不可以)安装部署,没有的话请进行安装部署并启动。完成…

DeSD:用于3D医学图像分割的深度自蒸馏自监督学习

文章目录 DeSD: Self-Supervised Learning with Deep Self-Distillation for 3D Medical Image Segmentation摘要本文方法Deep Self-DistillationDownstream Transfer Learning 实验结果 DeSD: Self-Supervised Learning with Deep Self-Distillation for 3D Medical Image Seg…

数据结构学习记录——集合及运算(集合的表示、并查集、树结构表示集合、集合运算、查找函数、并运算)

目录 集合的表示 集合运算概述 并查集 树结构表示集合 集合运算 查找函数 并运算 集合的表示 集合运算概述 交、并、补、差,判定一个元素是否属于某一个集合 并查集 集合并、查某元素属于什么集合 我们最主要关心的就是集合的两个运算,一个是把…

【网络原理】TCP原理

✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 目 录 🍃一. 确认应答🍂二. 超时重传🍁三. 连接管理🌿四. 滑动窗口🌻五. 流量控制🍀六. 拥塞控制&#x1f49…

量子计算:当前阶段仍属于热炒概念

一、量子计算为何可能会成为一个风口? 量子计算是利用量子力学原理进行计算的新型计算方式。与传统的经典计算机不同,量子计算机利用量子比特(qubits)进行信息处理,由于量子比特可以处于叠加态,这使得量子…

【英】考虑多能负荷不确定性的区域综合能源系统鲁棒规划(Python代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

携手共建数字钢铁,Hightopo亮相第三届钢铁展洽会

4 月 26 日备受期待的第三届钢铁展洽会在日照盛大召开。图扑软件作为智慧钢铁行业领先的 2D 和 3D 图形界面可视化解决方案提供商,受邀参与此次展会。 图扑软件携智慧钢铁三维可视化监控体系亮相“钢铁展洽会”,向众多钢铁企业展示了一系列图扑 HT 数字…

性价比最高的护眼台灯是哪款?最好的护眼台灯

不管你处在学生被动学习还是上班后主动学习的阶段,为自己挑选一款合适的台灯非常重要,因为夜晚的氛围能达到很高的学习效率,而台灯可以保证我们有一个舒适的阅读感受。那在为学习需求挑选台灯时,不应该以平价作为选购标准&#xf…

RTC 体验优化的“极值”度量与应用

随着线上互动需求的增加,直播连麦、语音/视频聊天的应用越来越广泛。我们一直在说“追求用户的极致体验”,但是体验是一个抽象的概念,很难量化和统计。如何从用户的行为中得到所在场景的优化“极值”,如何依据“极值”建立统一的质…

macOS Ventura 13.4 RC2(22F63)发布

系统介绍 根据黑果魏叔官网提供:5 月 12 日消息,苹果今天面向开发人员,发布了 macOS Ventura 13.4 的第 2 个候选 RC 版本(内部版本号 22F63),距离上个候选版本相隔数天时间。 macOS Ventura 带来了台前调…

VS2022安装NuGet 包

手动安装 在 解决方案资源管理器 中加载项目,然后选择“项目>管理 NuGet 包”。系统会打开“NuGet 包管理器”窗口。 2、 选择“ 浏览 ”选项卡, 使用左上角的搜索框搜索特定包。 从列表中选择一个包,在右侧窗格中显示其信息,…

MySQL(表的约束)

文章目录 0. 前言1. 空属性2. 默认值3. 列描述4. zerofill5. 主键6. 自增长7. 唯一键8. 外键 0. 前言 真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正…

【ChatGPTMidjourney】许多职业即将消失,AI 即将战胜人类了吗?

文章目录 前言一、人类科技发展史二、 AI浪潮下的挑战1. 数据安全和隐私保护问题2. 带来新的伦理和道德问题3. 版权和知识产权问题 三、对传统行业和就业的冲击1.传统文本编辑行业受到冲击2.就业岗位的变化3.工作流程的变化4.创意版权问题 四、AI浪潮下的机遇1.提高效率和创意性…

不用网闸、FTP的话 如何实现内外网数据交换?

网络隔离已然成为很多企业首选的数据保护方式,即使是内部人员之间,也是不能随意的发送敏感文件的。但是,文件的流转交互,又是不可避免的,网络隔离保障了企业网络安全,但在具体实践中仍需解决各隔离网间的数…

基于html+css图展示57

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…