【数据结构】栈及其实现

目录

🤠前言

什么是栈?

栈的定义及初始化

栈的定义

栈的初始化

栈的判空

栈顶压栈

栈顶出栈

栈的数据个数

栈的销毁

完整代码

总结


🤠前言

  • 学了相当长一段时间的链表,总算是跨过了一个阶段。从今天开始我们将进入栈和队列的学习,相比于链表可以说是有手就行的难度,所以各位老铁可以轻松一波啦,不必太担心。
  • 栈和队列我们分开来讲,本篇主要详解栈及其实现
  • 栈的特点是先进后出,后进先出(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);
	ps->a=NULL;
    ps->top=ps->capacity=0
}

完整代码

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);
	ps->a=NULL;
    ps->top=ps->capacity=0
}

总结

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[IOT物联网]Python快速上手开发物联网上位机程序——前言

一、什么是Python Python是一种简单易学、高级、通用的编程语言。它是一种解释型语言,不需要编译即可运行,因此可以快速地进行开发和测试。Python具有简洁优美的语法,使用它可以提高生产力和代码可读性。Python拥有强大的标准库和第三方库&am…

Linux Shell 实现一键部署virtualbox

VirtualBox 前言 VirtualBox 是一款开源虚拟机软件。VirtualBox 是由德国 Innotek 公司开发,由Sun Microsystems公司出品的软件,使用Qt编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。Innotek 以 GNU General Public Licens…

孙鑫VC++第四章 1.简单绘图-MFC消息映射机制

1. MFC消息映射机制 接下来将剖析MFC消息映射机制,探讨发送给窗口的消息是如何被MFC框架通过窗口句柄映射表和消息映射表来用窗口类的处理函数进行响应的。另外,还将讲述“类向导”这一工具的运用,讨论设备描述表及其封装类CDC的使用&#x…

玩转ChatGPT:魔改文章成果格式

一、写在前面 首先,我让小Chat替我吐槽一下: 科研人员天天都在填各种表格,简直成了我们的“表格王子”和“表格公主”。从申请项目、提交论文到汇报成果,表格无处不在。我们填表格的时候总是期待着它能让我们的工作更高效、更顺…

遇到一个同事,喜欢查其他同事的BUG,然后截图发工作大群里,还喜欢甩锅,该怎么办?...

职场上都有哪些奇葩同事? 一位网友吐槽: 遇到一个同事,喜欢查同级别同事的bug,截图发工作群,甚至发大群里,还喜欢甩锅,该怎么办? 职场工贼,人人喊打,网友们纷…

asm 加盘 udev 重启 导致网络异常

Network interface going down when dynamically adding disks to storage using udev in RHEL 6 (Doc ID 1569028.1)正在上传…重新上传取消To Bottom In this Document APPLIES TO: Oracle Database - Enterprise Edition - Version 11.2.0.3 and later Oracle Net Servi…

UART驱动情景分析-read

一、源码框架回顾 shell读数据,一开始的时候没有就休眠。数据从串口发送到驱动,驱动接收到中断,驱动读取串口数据,这个数据会传给行规程。 行规程获取到数据后,会回显。按下删除就删除一个字符,按下回车&am…

【Linux升级之路】3_Linux进程概念

🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux升级之路】 ✒️✒️本篇内容:认识冯诺依曼系统,操作系统概念与定位,深入理解进程概念(了解PCB&…

【#ifndef, #define, 和 #endif】

前言 学习AFNetWoring源码的时候,在AFN的h借接口文件又看到了这几个宏定义,学习记录一下。 作用 #ifndef, #define, 和 #endif是C/CPP的预处理指令,常常用来条件编译和防止头文件重复包含。 简介 #ifndef 它是if not define的简写&…

Cy5.5-PEG-SH近红外荧光PEG试剂 Cyanine5.5-PEG-SH,Thiol-PEG-Cy5.5可用于活体成像

Cy5.5-PEG-SH ,Cy5.5聚乙二醇巯基 英文名称:Cy5.5-PEG-SH 中文名称:Cy5.5聚乙二醇巯基 性状: 深蓝色固体或粘性液体,取决于分子量 溶剂:溶于水、 DMSO等常规性有机溶剂 激发/发射波长:684 nm/710 nm …

学习HCIP的day.06

十一、OSFP扩展知识点 1、关于OSPF状态机的问题 (1)在MA网络中(要进行DR/BDR选举)存在7种状态机,init是路由器A收到邻居B的hello包,但该hello包中没有A的RID; (2)在点到…

js跨域的解决方案

一、什么是跨域? 指的是浏览器不能执行其他网站的脚本,简单来说是浏览器同源政策的限制,浏览器针对于ajax的限制。 同源政策 两个页面拥有相同的 协议,端口,域名 就是同源,如果有一个不相同就是不同源…

手把手教你用代码画架构图 | 京东云技术团队

作者:京东物流 覃玉杰 1. 前言 本文将给大家介绍一种简洁明了软件架构可视化模型——C4模型,并手把手教大家如何使用代码绘制出精美的C4架构图。 阅读本文之后,读者画的架构图将会是这样的: 注:该图例仅作绘图示例使…

【PCIE体系结构十一】部分物理层发送接收逻辑细节

👉个人主页:highman110 👉作者简介:一名硬件工程师,持续学习,不断记录,保持思考,输出干货内容 参考书籍:《PCI.EXPRESS系统体系结构标准教材 Mindshare》 目录 物理层…

【复杂网络建模】——通过图神经网络来建模分析复杂网络

目录 一、复杂网络介绍 二、复杂网络建模分析方法 三、基于图神经网络来建模 1、数据准备 2、构建图神经网络模型 3、学习节点和边的表示 4、特征提取和预测 5、模型评估和优化 四、可视化建模分析 1、初始网络可视化 2、特征可视化 一、复杂网络介绍 复杂网络是指…

软件测试专业应届生应如何提高职场竞争力

一:巩固专业知识 背景:笔者已经做了几年的打工人,以个人经验给软件测试专业应届生一些建议。 推荐需要掌握的知识: 1、软件测试基础知识(软件生命周期每个阶段工作需了解) 2、熟悉SQL/MySQL/Oracle数据库&…

【C++】哈希/散列详细解析

前言:上篇文章介绍了unordered_set和unordered_map序列关联式容器,它们之所以效率比较高,是因为其底层使用了哈希结构。,所以这篇文章我们就来详细讲解一下哈希表。有关unordered序列关联式容器的知识,请移步至这篇文章…

python3+pytest+requests+allure+yaml测试框架搭建

目录 设计框架的原则 1.框架整体结构 2.框架各个模块说明 3.示例 3.1 先写一个测试用例 3.2 对上面的用例进行分层封装(可根据业务复杂度分两层或者三层,此处演示分三层) 3.3生成allure测试报告并查看 设计框架的原则 封装基类方法 对…

山东移动:全业务域核心系统升级,实现大幅降本增效

本文介绍了山东移动引入 OceanBase 到山东省 BOSS/CRM 核心系统领域的相关情况。欢迎访问 OceanBase 官网获取更多信息:https://www.oceanbase.com/ 中国移动通信集团山东有限公司(以下简称"山东移动") 隶属于中国移动通信集团公司…

发现一个国产BI软件,做财务数据分析效果绝了

如果是一般的财务数据分析,BI软件们都能做,但如果真要深入了解财务痛点,逐个击破财务数据分析难点,实现多维立体自助式的财务数据分析,那就难。就目前而言,财务数据分析做得好的国产BI软件也就一个奥威BI软…