【数据结构】栈及其实现

news2024/11/29 3:52:11

目录

🤠前言

什么是栈?

栈的定义及初始化

栈的定义

栈的初始化

栈的判空

栈顶压栈

栈顶出栈

栈的数据个数

栈的销毁

完整代码

总结


🤠前言

  • 学了相当长一段时间的链表,总算是跨过了一个阶段。从今天开始我们将进入栈和队列的学习,相比于链表可以说是有手就行的难度,所以各位老铁可以轻松一波啦,不必太担心。
  • 栈和队列我们分开来讲,本篇主要详解栈及其实现
  • 栈的特点是先进后出,后进先出(LIFO),这一特点以及进一步运用(单调栈)是一些算法题的突破口,后续我也会分享LeetCode的一些题,希望大家关注点点,以免错过哦!

什么是栈?

我们前面学习的顺序表(数组)以及链表可以说是数据结构的物理结构,而栈和队列则是数据结构的逻辑结构。

这是什么意思呢?

如果把数据结构比作活生生的人,那么物理结构就是人的血肉和骨骼,看得见摸得着,在内存中也实际存储这;逻辑结构则是思想灵魂,看不见摸不着,它依赖于物理结构而存在。

简而言之,栈和队列其实都是由数组或者链表实现的,不过在此基础上加了一些限制条件以适用于不同场景,将其抽化成了一个数据结构

栈的定义及初始化

栈的定义

  • 我们采用数组的方式实现栈,因为数组比链表的缓存命中率更高(粗暴点来说cpu访问的速度会更快,访问没用的信息的数量会减少,这里就不具体展开了)。
  • 还是定义一个结构体来实现栈,分别为数组(此处应该用malloc,这样不够的时候可以扩容)
  • top用来表示栈顶,因为栈只在栈顶一段进行操作
  • capacity用来记录栈的容量。
typedef int STDataType;
typedef struct Stack
{
	int top;
	int capacity;
	STDataType* a;
}ST;

栈的初始化

  • 在进行插入的时候再开辟空间,为了防止野指针问题,将a置为NULL,capacity显而易见应该也为0
  • 关于top就有一点讲究,如果top置为0则指向最后一个数据的下一个,如果置为-1指向最后一个有效数据。因为每次插入数据后top才++,不是很理解的小伙伴们可以画一个数组模拟一下。
  • 我们这里就将top初始化为0,其也间接体现了存储数据的个数
  • 当然传进来的栈不能为空指针啦,不然相当于栈都还没创建,老生常谈的问题了,每个函数接口前都要assert暴力断言一下,下文就不赘述了

以下为函数接口实现:
 

void StackInit(ST* ps)
{
	assert(ps);

	ps->capacity = ps->top = 0;//指向最后一个数据的下一个
	ps->a = NULL;
}

栈的判空

上文提到top间接表示了存储数据的个数,所以我们直接判断top是否为0即可。

以下为函数接口实现:

bool StackEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

栈顶压栈

  • 在数据结构中的学习当中,插入数据往往需要考虑扩容的问题,此处也是。当top==capacityd的时候我们就扩容
  • 插入后top需要++一下,而扩容后capacity则需要更新(易忘)
  • 这里应该包括了当top==0的情况,因为初始化的时候没有开辟空间

什么是栈/Java中的栈(栈定义/栈的时间复杂度/实现一个栈/栈的动态扩容)含示例代码_Isaac_Gao的博客-CSDN博客

 

以下为函数接口实现:

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	
	//当内存满了则需要扩容
	if (ps->top== ps->capacity)
	{
		int newcapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
		STDataType *tmp=(STDataType*)realloc(ps->a, newcapacity);
		if (tmp == NULL)
		{
			perror("malloc fail\n");
			return;
		}
		else
		{
			ps->capacity = newcapacity;
			ps->a = tmp;
		}
	}
	//没满就直接压栈即可
	ps->a[ps->top] = x;
	ps->top++;
}

栈顶出栈

  • 删除数据,往往需要考虑数据结构是否为空的情况,这里就可以用到上文的StackEmpty函数接口了,增加了代码的可读性
  • 和顺序表删除数据一样,只需要top--即可,并不需要真的抹除其数据,下次入栈的时候新的数据就会覆盖原来的数据。
  • capacity不需要变化,因为其表示栈的容量

以下为函数接口实现:

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

栈的数据个数

  • 上文说了top初始化为0的时候代表数据个数,所以这里直接返回top即可
  • 数据个数一定为整数,所以用int即可,unsigned int也行

以下为函数接口实现:

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

获取栈顶元素

  • 函数返回类型应该为数组存储的数据类型,而不要思维固化的写为int
  • 因为top初始化为0,指向最后一个数据的下一个位置,所以我们要返回top-1位置的数据
  • 当栈为空的时候肯定获取不了啦,所以这里还是assert断言爆打

以下为函数接口实现:

STDataType StackTop(ST* ps)//获得栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->a[ps->top-1];
}

栈的销毁

切记不可直接free掉代表栈的结构体就以为把栈销毁了,要先free掉结构体里的数组,然后再free掉代表栈的结构体,不然会内存泄漏!!!

以下为函数接口实现:

void StackDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	free(ps);
}

完整代码

void StackInit(ST* ps)
{
	assert(ps);

	ps->capacity = ps->top = 0;//指向最后一个数据的下一个
	ps->a = NULL;
}

bool StackEmpty(ST* ps)
{
	assert(ps);

	return 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=(STDataType*)realloc(ps->a, newcapacity);
		if (tmp == NULL)
		{
			perror("malloc fail\n");
			return;
		}
		else
		{
			ps->capacity = newcapacity;
			ps->a = tmp;
		}
	}
	//没满就直接压栈即可
	ps->a[ps->top] = x;
	ps->top++;
}
void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}
STDataType StackTop(ST* ps)//获得栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->a[ps->top-1];
}
int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

void StackDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	free(ps);
}

总结

😊相比于链表,栈实现起来简直不要简单太多,但是大家别懈怠,后面还有二叉树在等着我们呢,现在只是过渡期,继续努力哦!

❤️我也会继续输出数据结构相关的博客的,希望大家多多支持!!!

感谢阅读本小白的博客,如果错误请指出,一定虚心采纳!

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

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

相关文章

什么是AIGC

AIGC是人工智能创意生成的缩写(Artificial Intelligence Generated Creativity),指的是利用人工智能技术实现的创意生成。通俗来说,就是让机器产生新颖、独特且有创造性的作品或方案,例如音乐、绘画、视频、文本等等。…

Sui基金会宣布面向APAC的Office Hours计划

诚挚邀请构建者与Sui基金会的Growth团队一起开启“Office Hours”计划,共同努力,迈向业务增长的下一步。 Sui基金会致力于推动Sui在全球范围内的普及。为此,我们通过积极支持开发人员的开发者资助计划、Builder House和大使计划在Sui上开始…

如何高效运行Omniverse,无惧本地硬件压力

无论是创造能够表达原始情感的逼真数字人,还是构建身临其境的虚拟世界,全球设计、工程、创意和其他行业的人士都在通过3D工作流,突破技术壁垒并拓展创意可能,让虚拟世界和现实世界交融与观众产生共鸣。 而在众多连接未来创作内容的…

ES6中函数新增的方式方法

1.1函数形参的默认值 1.1.1基本用法 ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。如下代码: function func(x,y){y y || "tom";console.log(x,y);}func("hello"); //hello tomfunc("…

数据库标准化之核心结局变量集(COS)

COS介绍 核心结果集(COS)是在特定健康状况下进行的所有临床试验中应测量和报告的一组最少结局变量集。COS数据库是这些变量集的集合,这些集合是通过循证和迭代过程开发的。该数据库由COMET倡议维护,该计划是研究人员,…

Linux 系统上 C 程序的编译与调试 2 总结

1.gcc分布编译链接 (1) 预编译 : gcc -E main.c -o main.i (2) 编译: gcc -S main.i -o main.s (3) 汇编: gcc -c main.s -o main.o (4) 链接: gcc main.o -o main gcc -E hello.c -o hello.i #预处理 gcc -S hello.i -o h…

【FMC134】ADC12DJ3200之4通道3.2GSPS(2 通道6.4GSPS) 12 位AD高速采集子卡设计原理图及调试经验

板卡概述 FMC134 是一款4 通道3.2GSPS(或者配置成2 通道6.4GSPS)采样率的12 位AD 采集FMC子卡模块,该板卡为FMC标准,符合VITA57.4 规范,可以作为一个理想的IO 模块耦合至FPGA 前端,射频模拟信号数字化后通过…

【多线程进阶一】常见的锁策略

目录 一、常见的锁策略 🍅1、常见的锁策略 🍅2、Synchronized实现了哪些锁策略? 🍅3、自旋锁的实现方式—CAS (1)CAS伪代码 (2)演示 使用CAS方式来实现自增操作: &am…

Linux 系统修改环境变量的方法

1. Linux 系统修改环境变量 正常情况下改变环境变量可以修改的文件有两类: 第一类是 “系统的全局环境变量”,修改之后可作用于整个系统包含的所有用户都会生效;(文件:/etc/profile) 第二类是 “局部环境变量”,也就…

Linux C程序多文件编译

C程序多文件编译 在Linux平台C编程,实现求两数最大值和两数之和的功能 1.编写add.c wysDESKTOP-2OU3HRV:~/mycode/day02$ vi add.c1 int add(int x,int y)2 {3 return x y;4 } 2.编写头文件add.h wysDESKTOP-2OU3HRV:~/mycode/day02$ vi add.hint add(…

Python 实验五 字符串与正则表达式

1.输入一个字符串,将该字符串中下标为偶数的字符组成新串并通过字符串格式化方式显示。 a input("请输入一个字符串:") b a[1::2] print("老串为:%a,新串为:%a"%(a,b))2.编写程序,生…

LInux系统下使用git的三板斧以及报错处理

LInux使用git 我们应该知道git是什么东西,还有git的三板斧,git是一个工具,使用git来将文件上传到代码仓库 文章目录 LInux使用gitcloneaddcommitpush查看当前git的状态 clone 第一步找到你创建的仓库,然后复制http地址&#xf…

目前可以用的ChatGPT网址大全

ChatGPT是一个基于人工智能的聊天机器人,可以与用户进行自然语言交互。它可以回答各种问题,提供有用的信息和建议,还可以进行闲聊和娱乐。ChatGPT使用最先进的自然语言处理技术,可以理解和解释人类语言,从而提供准确和…

【Linux】IO多路转接 - epoll

文章目录 I/O多路转接之epollepoll初识epoll的相关系统调用函数epoll_createepoll_ctlepoll_wait epoll工作原理epoll服务器-*epoll的优缺点epoll工作方式对比LT和ET I/O多路转接之epoll epoll初识 epoll也是系统提供的一个多路转接的接口,epoll才是使用和面试的重点,在效率和…

SpringBoot【开发实用篇】---- 整合第三方技术(缓存)

SpringBoot【开发实用篇】---- 整合第三方技术(缓存) SpringBoot内置缓存解决方案手机验证码案例SpringBoot整合Ehcache缓存SpringBoot整合Redis缓存SpringBoot整合Memcached缓存SpringBoot整合jetcache缓存纯远程方案纯本地方案本地远程方案远程方案的数…

tomcat控制台打印乱码解决

一、注册表修改 HKEY_CURRENT_USER ->console ->tomcate 新增 32位 CodePage 16进制 fde9 二、idea 中配置 Tomcat 后启动服务,输出打印日志乱码问题 解决办法: ①、打开安装idea文件路径,在bin目录下,找到下面两个文件 ②…

图像动态裁剪

1. 背景 以两级级联模型为例,第一级目标检测模型用于检测人员,第二级目标检测模型用于检测手机、对讲机等。然后实际数据采集过程中,手机、对讲机这些设备并不在人员的一级检测框内,使得二级模型训练的样本较少。 二级目标检测模…

详细讲解,接口自动化—Requests之Cookie鉴权关联接口实战

目录 前言: 一、 简介 二、 实战操作 1. 登录接口 2. 查询订单接口 3. 新增订单接口 4. 修改订单接口 5. 删除订单接口 三、 结束语 前言: 接口自动化测试是软件测试过程中的重要一环,现在越来越多的公司开始使用自动化测试来提高测…

Gigabyte Z490 Vision D i9-10900k电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网,转载需注明出处。(下载请直接百度黑果魏叔) 硬件型号驱动情况 主板Gigabyte Z490 Vision D 处理器Intel i9-10900k已驱动 内存64GB G.Skill Trident Z 3600Mhz CL18已驱动 硬盘西数 WDS250G3X0C-00SJG0 ( SN750) …

cad文件怎么转换成pdf格式?一键操作的4个方法

在很多时候,我们为了能够更好地查看CAD图纸,需要将其格式转换为PDF。所以说,CAD文件格式的转换是非常关键的。首先,将CAD转换为PDF格式能够有效提升文件的兼容性。CAD软件通常需要特定的软件才能打开和编辑,而PDF格式则…