深入浅出带你玩转栈与队列——【数据结构】

news2024/11/15 17:54:43

W...Y的主页 😊

代码仓库分享 💕


目录

1.栈

1.1栈的概念及结构

1.2栈的结构特征图 

​编辑 1.3栈的实现

1.3.1栈的初始化

1.3.2进栈

1.3.3出栈

1.3.4销毁内存

1.3.5判断栈是否为空

1.3.5栈底元素的读取

1.3.6栈中大小

1.4栈实现所有接口

2.队列

2.1队列的概念

2.2队列的结构 

 2.3队列的实现

2.3.1队列的接口总览

2.3.2队列的初始化

 2.3.3入队

2.3.4出队

2.3.5获取对头元素

2.3.6获取对尾元素

2.3.7判断是否为空

2.3.8队列销毁

3.拓展内容


 

在前几期的学习中,我们学习了顺序表与链表,今天我们将学习一种新的数据结构——栈与队列。而栈与队列实际上就是链表的一种变形产物,但肯定会有许多结构上的不同。

现在就让我们进入栈和队列,看看它们的特点!!!

1.栈

1.1栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

1.2栈的结构特征图 

文字力量有时太过渺小,我们通过图解更清楚的了解栈的特点。

 1.3栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

1.3.1栈的初始化

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

这里我们使用数组作为结构,更好的适用于栈的特征。但是这又与顺序表中的不同,顺序表在刚进入就进行了开辟空间,而我们栈的初始化先全部设为0。

1.3.2进栈

在进栈时,我们会遇到栈内存满的情况,所以我们必须进行判断(top 有效内容与 capacity容量是否相等),如果相等我们就进行realloc进行扩容即可。然后将需要放入栈的内容存入堆区,有效内容top++即可完成。如果内容开始为0,我们使用三元表达式直接扩容为4。

void STPush(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, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		ps->a[ps->top] = x;
		ps->top++;
	}
}

注意:malloc与realloc都可以使用,当给予realloc一个指针时,功能完全相同

1.3.3出栈

出栈非常简单,只需要将top--,不去访问其内容即可。

void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	--ps->top;
}

1.3.4销毁内存

销毁堆上内存也非常简单,只需free掉即可

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

但是我们一定要用assert进行断言,防止传入空指针。

1.3.5判断栈是否为空

栈中是否插入内容,我们可以创建一个函数进行判断一下。返回值为bool类型,我们需要在头文件中加入#include<stdbool.h>才可以使用。

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

1.3.5栈底元素的读取

在读取栈底元素时,我们需要检查传入栈的指针是否正确以及栈中是否为空,两个必须都为真即可进行下面操作。

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

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

栈底元素就是top-1的内容,我们直接返回即可。

1.3.6栈中大小

当我们一直添加数据,需要了解栈中有多少个有效数据时,我们却束手无策,所以我们还需要一个能测出栈中大小函数。

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

	return ps->top;
}

1.4栈实现所有接口

我们需要了解的所有接口,可以放在头文件中:

// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;
#define N 10
typedef struct Stack
{
 STDataType _a[N];
 int _top; // 栈顶
}Stack;
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
 STDataType* _a;
 int _top; // 栈顶
 int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps); 

2.队列

2.1队列的概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

2.2队列的结构 

 2.3队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。

2.3.1队列的接口总览

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Que;

void QueueInit(Que* pq);
void QueueDestroy(Que* pq);
void QueuePush(Que* pq, QDataType x);
void QueuePop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
bool QueueEmpty(Que* pq);
int QueueSize(Que* pq);


在这里使用单链表,作为队列结构。队列特点就是先进先出,但是单链表比较适合头插头删,并不适合尾删,所以我们创建另一个结构体记录尾结点和头节点,这样也可以避免使用二级指针增加难度。

2.3.2队列的初始化

初始化我们先把所有内容设置成NULL或0即可

void QueueInit(Que* pq)
{
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

 2.3.3入队

入队其实就是链表中的尾插!!!

void QueuePush(Que* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

我们一定要记得将记录首尾的结构体进行赋值,分情况进行,不要忘记更新哦!!!

2.3.4出队

出队就是链表中的头删

void QueuePop(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}

 我们一定要注意当删到只有一个内容节点时,要处理尾指针指向NULL。

2.3.5获取对头元素

只需要判断队列存指针正确且不为空,直接返回head指向的data即可。 QueueEmpty函数就是判断队列是否为空的函数,在后面有代码展示!!!

QDataType QueueFront(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return ps->head->data;
}

2.3.6获取对尾元素

尾元素获取与首元素基本相同。

QDataType QueueBack(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return ps->tail->data;
}

2.3.7判断是否为空

bool QueueEmpty(Que* pq)
{
	assert(pq);
	return ps->tail == NULL;
}

2.3.8队列销毁

一定不要忘记创建的存放头尾节点的指针结构体,也要将它们置空

void QueueDestroy(Que* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = ps->tail = NULL;
	pq->size = 0;
}

3.拓展内容

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型 时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。 

  

栈、队列、顺序表、链表都是相似但不同的数据结构,我们在学习时一定要了解其中的差异,这样才能在以后更好的应用!!!

以上就是本节全部内容,感谢大家耐心观看,你们的三连支持是博主最大创作动力。

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

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

相关文章

时序预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现SO-CNN-BiL…

增强数字风险防护管理,天际友盟牵头正式发布GDN·全球数字风险阻断网络

随着数字化进程的加快&#xff0c;企业对于数字风险防护管理的需求与日俱增&#xff0c;其数字足迹、数字资产&#xff0c;甚至高管的个人形象都可能成为不法分子的攻击目标。保护关键数字资产与数据免受外部威胁&#xff0c;提升在线业务运营稳健性的价值毋庸置疑。 8月18日&a…

QQ音乐刷时长和音响力工具-无需密码

QQ音乐刷等级是一款安卓端的QQ音乐刷时长和音响力工具&#xff0c;使用时无需密码登录&#xff0c;直接输入qq号码即可&#xff0c;支持微信账号&#xff0c;每提交一次可以刷99分钟的听歌时长&#xff0c;实时到账&#xff0c;刷的听歌时长可以增加听歌排行榜跟音响力(就是QQ音…

辅助笔记-安装Ubantu20.04.1虚拟机

安装Ubantu20.04.1虚拟机 文章目录 安装Ubantu20.04.1虚拟机步骤一&#xff1a;检查BIOS虚拟化支持步骤二&#xff1a;VMware17安装虚拟机步骤1&#xff1a;新建虚拟机步骤2&#xff1a;验证虚拟机能否上网 步骤三&#xff1a;设置Ubantu语言为中文步骤四&#xff1a;软件仓库镜…

江西景德镇陶瓷三维扫描工艺品瓷器数字化3D打印-CASAIM中科广电

江西景德镇陶瓷是中国著名的传统陶瓷产地&#xff0c;其瓷器作为文化遗产具有重要的历史和艺术价值。对于陶瓷工艺品瓷器的三维扫描和数字化&#xff0c;利用三维激光扫描和3D打印相结合的方式助力文物数字化及复原领域是目前主流的发展趋势。 1. 三维激光扫描操作&#xff1a;…

编织梦想:SpringBoot AOP 教程与自定义日志切面完整实战

什么是 AOP AOP 是指通过预编译方式和运行期动态代理的方式&#xff0c;在不修改源代码的情况下对程序进行功能增强的一种技术。AOP 不是面向对象编程&#xff08;OOP&#xff09;的替代品&#xff0c;而是 OOP 的补充和扩展。它是一个新的维度&#xff0c;用来表达横切问题&a…

一文看懂群晖 NAS 安装 Mysql 远程访问连接

文章目录 1. 安装Mysql2. 安装phpMyAdmin3. 修改User 表4. 本地测试连接5. 安装cpolar6. 配置公网访问地址7. 固定连接公网地址 群晖安装MySQL具有高效、安全、可靠、灵活等优势&#xff0c;可以为用户提供一个优秀的数据管理和分析环境。同时具有良好的硬件性能和稳定性&#…

spring boot 3使用 elasticsearch 提供搜索建议

业务场景 用户输入内容&#xff0c;快速返回建议&#xff0c;示例效果如下 技术选型 spring boot 3elasticsearch server 7.17.4spring data elasticsearch 5.0.1elasticsearch-java-api 8.5.3 pom.xml <dependency><groupId>org.springframework.boot</gr…

如何快速搭建一个预约系统?

如何快速搭建一个预约系统 ? 线上预约系统的出现&#xff0c;为解决线下排队拥堵问题提供了便利和解决方案。通过线上预约&#xff0c;人们可以提前预约时间段&#xff0c;避免了到场后需要长时间等待的情况。以下是线上预约解决线下排队拥堵问题的几个场景&#xff1a; 餐厅…

深入完整的带你了解java对象的比较

目录 元素的比较 1.基本类型的比较 2.对象比较的问题 1.运行结果 2.疑问 3.原因 对象的比较 1.覆写基类的equals 2.基于Comparble接口类的比较 3.基于比较器比较 4.三种方式对比 元素的比较 1.基本类型的比较 在Java 中&#xff0c;基本类型的对象可以直接比较大…

52所韩国大学联合退出QS世界大学排名

因今年QS的全新评估指标&#xff0c;令韩国大学在世界大学的排名中大幅下降&#xff0c;因此韩国52所大学联合发表声明&#xff0c;将不再参加QS世界大学排名。下面知识人网小编做详细介绍。 今年6月28日&#xff0c;QS教育集团正式发布了2024年世界大学排名&#xff0c;见“排…

609. 在系统中查找重复文件

609. 在系统中查找重复文件 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 609. 在系统中查找重复文件 https://leetcode.cn/problems/find-duplicate-file-in-system/description/ 完成情况&#xff1a; 解题思…

网络编程(三次握手、四次挥手)

一、Wireshark 窗口介绍 二、 wireshark与对应的OSI七层模型 服务器和客户端的代码不能都运行在ubuntu&#xff0c;因为wireshark抓的是流经真实网卡的数据包。 若将服务器客户端都运行在ubuntu&#xff0c;数据直接经过虚拟网卡通信&#xff0c;而不会经过真实网卡。 三、以太…

QT样式表(一)

目录 QSS样式表设置 1、概念 1、通过UI设计器的可视操作修改 2、通过代码修改 3、从样式文件加载 2、样式表语法 选择器的类型 3、设置背景图片 1、添加资源文件 2、使用label控件 显示头像&#xff0c;在样式表文件中进行设置 3、在项目中添加图片资源 QSS样式表设…

动态规划入门之二维数组的动态规划(过河卒)

P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 过河卒&#xff0c;首先科普一下象棋里面的马的跳跃一步的规则吧&#xff08;这题真够坑人的&#xff0c;连个规则都不给出&#xff0c;害得我第一次交就全wa&#xff09;。一张图解释 大家看所…

Nvidia Jetson 编解码开发(4)H265解码图像异常问题调试

1. 前言 基于此贴继续验证H265图像 Nvidia Jetson 编解码开发(3)解决H265解码报错“PPS id out of range”_free-xx的博客-CSDN博客 ffmpeg解码后图像颜色异常 2. 梳理YUV格式顺序 相机输出图像格式: YUV422 8bit, UYVY 由于编码模块输入必须是 YUV420, 不能是YUV…

SpringCloud Ribbon中的7种负载均衡策略

SpringCloud Ribbon中的7种负载均衡策略 Ribbon 介绍负载均衡设置7种负载均衡策略1.轮询策略2.权重策略3.随机策略4.最小连接数策略5.重试策略6.可用性敏感策略7.区域敏感策略 总结 负载均衡通器常有两种实现手段&#xff0c;一种是服务端负载均衡器&#xff0c;另一种是客户端…

内网渗透神器CobaltStrike之权限提升(七)

Uac绕过 常见uac攻击模块 UAC-DLL UAC-DLL攻击模块允许攻击者从低权限的本地管理员账户获得更高的权限。这种攻击利用UAC的漏洞&#xff0c;将ArtifactKit生成的恶意DLL复制到需要特权的位置。 适用于Windows7和Windows8及更高版本的未修补版本 Uac-token-duplication 此攻…

软件测试开发实战|接口自动化测试框架开发(pytest+allure+aiohttp+用例自动生成)

近期准备优先做接口测试的覆盖&#xff0c;为此需要开发一个测试框架&#xff0c;经过思考&#xff0c;这次依然想做点儿不一样的东西。 接口测试是比较讲究效率的&#xff0c;测试人员会希望很快能得到结果反馈&#xff0c;然而接口的数量一般都很多&#xff0c;而且会越来越…

鼎友餐饮信息总监杨山海:餐饮新增长依托数智应用,用数字化打造单店盈利模型

杨山海 鼎友餐饮信息总监 近20年餐饮行业信息化、数字化决策经验&#xff0c;曾担任新辣道、雕刻时光、青年餐厅、快乐蜂、鲜果时间信数化负责人&#xff0c;主抓数字化转型、系统选型、多接口系统管理等&#xff0c;拥有丰富的餐饮行业数字化转型经验。 2000年&#xff0c;杨…