栈和队列-介绍与实现(超级!!!详解-C语言)

目录

栈的介绍

        栈的概念

        栈的结构

栈的实现

        初始化栈 StackInit

        销毁栈 StackDestroy

        入栈 StackPush

        出栈 StackPop

        获取栈顶元素 StackTop

        检查栈是否为空 StackEmpty

        获取栈中有效元素个数 StackSize

队列

队列的介绍

        队列的概念

        队列的结构

        队列的应用

队列的实现

        初始化队列 QueueInit

        销毁队列 QueueDestroy

        队尾入队列 QueuePush

        队头出队列 QueuePop

        获取队列头部元素 QueueFront

        获取队尾尾部元素

        检查队列是否为空 QueueEmpty

        获取队列中有效元素个数 QueueSize


栈的介绍

        栈的概念

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

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

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

        栈的结构

栈的实现

        初始化栈 StackInit

        需要用结构体创建一个栈,这个结构体需要包括栈的基本内容(栈,栈顶,栈的容量)。

typedef int STDataType;//栈中存储的元素类型(这里用整型举例)typedef struct Stack
{STDataType* a;//栈int top;//栈顶int capacity;//容量,方便增容
}Stack;

        然后需要一个初始化函数,对刚创建的栈进行初始化。 

//初始化栈
void StackInit(Stack* pst)
{// 使用断言检查输入指针是否有效,确保不为空assert(pst);// 动态分配内存,为栈分配空间,初始可存储4个STDataType类型的元素pst->a = (STDataType*)malloc(sizeof(STDataType)* 4);// 初始化栈顶指针为0,表示栈当前为空,没有元素pst->top = 0;// 设置栈的初始容量为4,即栈目前最多可以容纳4个元素pst->capacity = 4;
}

        销毁栈 StackDestroy

        因为栈的内存空间是动态开辟出来的,当我们使用完后必须释放其内存空间,避免内存泄漏。

void StackDestroy(Stack* pst) 
{// 断言检查传入的栈结构体指针是否有效,确保它是指向一个已初始化的栈assert(pst != NULL);// 使用 free 函数释放栈中存储元素的数组所占用的内存防止内存泄漏free(pst->a);// 将栈的元素数组指针置为 NULL,这是一种安全措施,避免栈被释放后仍被当作有效指针使用pst->a = NULL;// 将栈顶指针 top 置为 0,这表示栈内已无任何元素,栈处于空状态pst->top = 0;// 将栈的容量 capacity 置为 0,代表栈当前没有存储能力,明确表示栈已经被销毁pst->capacity = 0;
}

        入栈 StackPush

        进行入栈操作前,我们需要检测栈的当前状态,若已满,则需要先对其进行增容,然后才能进行入栈操作。

void StackPush(Stack* pst, STDataType x) 
{// 断言检查栈结构体指针是否有效assert(pst);// 判断栈是否已满(栈顶索引等于栈的当前容量)if (pst->top == pst->capacity) {// 如果栈满,则尝试重新分配内存,使栈容量翻倍STDataType* tmp =(STDataType*)realloc(pst->a,sizeof(STDataType)*pst->capacity * 2);// 检查重新分配内存是否成功if (tmp == NULL) {// 若失败,输出错误信息,并调用 exit 函数结束程序运行printf("realloc fail\n");exit(-1);}// 若重新分配内存成功,更新栈的元素数组指针和容量pst->a = tmp;pst->capacity *= 2;}// 将新元素存入栈顶位置pst->a[pst->top] = x;// 更新栈顶索引,表示栈顶已移动至新的元素处pst->top++;
}

        出栈 StackPop

        出栈操作比较简单,即让栈顶的位置向下移动一位即可。但需检测栈是否为空,若为空,则不能进行出栈操作。

void StackPop(Stack* pst) 
{// 断言检查栈结构体指针是否有效assert(pst);// 断言检查栈是否为空,若为空则无法弹出元素assert(!StackEmpty(pst));// 栈顶指针向下移一位,相当于删除栈顶元素// 注意:这里假设移除元素后不需要返回其值,且不涉及内存释放pst->top--;// 注:在实际应用中,若栈顶元素包含动态分配的内存,此处还需要额外处理释放该内存
}

        获取栈顶元素 StackTop

        获取栈顶元素,即获取栈的最上方的元素。若栈为空,则不能获取。

STDataType StackTop(Stack* pst) 
{// 断言检查栈结构体指针是否有效assert(pst);// 断言检查栈是否为空,若为空则无法获取栈顶元素assert(!StackEmpty(pst));// 返回栈顶元素的值,栈顶元素的位置是栈顶指针减1// 注意:此处只读取栈顶元素而不改变栈的状态return pst->a[pst->top - 1];
}

        检查栈是否为空 StackEmpty

        检测栈是否为空,即判断栈顶的位置是否是0即可。若栈顶是0,则栈为空。

bool StackEmpty(Stack* pst) 
{// 断言检查栈结构体指针是否有效assert(pst);// 根据栈顶指针 top 的值判断栈是否为空// 当栈顶指针为 0 时,表示栈中没有元素,即栈为空return pst->top == 0;
}

        获取栈中有效元素个数 StackSize

        因为top记录的是栈顶,使用top的值便代表栈中有效元素的个数。

int StackSize(Stack* pst) 
{// 断言检查栈结构体指针是否有效assert(pst);// 栈顶指针 top 的值直接表示栈中有效元素的个数// 因为每当有元素入栈时,top加1;元素出栈时,top减1// 所以,top的值就反映了当前栈内实际存储了多少个元素return pst->top;
}

队列

队列的介绍

        队列的概念

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

        入队列:队列的插入操作叫做入队列,进行插入操作的一端称为队尾。

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

        队列的结构

        队列的应用

        队列在生活中的运用非常广泛。很大一部分医院、营业厅以及餐厅等场所都存在队列的应用。
        例如,医院的采血环节的流程就运用了队列。在医院,如果我们要去抽血,我们首先要在旁边的抽号机抽取自己的编号,当某一个抽血窗口叫到你时,你便可以去抽血了。
        在这个过程中,当你在抽号机抽取到某一个编号,那么这个编号这时就从队尾入队列,当某一窗口抽血结束后,会在该队列中拿走一个编号并叫该编号的人到这个窗口接受抽血,那么这时这个编号就从队头出队列。

队列的实现

        首先我们需要创建一个结点类型,类型包含了该结点的数据和指向下一结点的指针。

typedef int QDataType;typedef struct QListNode
{// 指向下一个节点的指针struct QListNode* next;// 节点所存储的数据QDataType data;
} QListNode;

        队列与普通链表又有所不同,普通链表只需要知道链表的头指针,而队列的信息包括了队头和队尾,所以我们需要再创建一个结构体用于存放队列的队头和队尾。 

typedef struct Queue
{// 队列头指针// 指向队列的第一个节点,当队列为空时,head 和 tail 都指向 NULLQListNode* head;// 队列尾指针// 指向队列的最后一个节点,每次有新元素入队时,都会更新 tail 指针QListNode* tail;
} Queue;

        初始化队列 QueueInit

         然后需要一个初始化函数,对刚创建的队列进行初始化。

void QueueInit(Queue* pq) 
{// 断言检查传入的队列结构体指针是否有效assert(pq);// 将队列的头指针 head 初始化为 NULL,表示队列当前为空,无元素pq->head = NULL;// 将队列的尾指针 tail 也初始化为 NULL,与 head 一致,表示队列为空// 这样设计的原因是,在队列为空时,头尾指针均指向 NULL;而在有元素入队时,tail 指针将指向最后一个元素pq->tail = NULL;
}

        销毁队列 QueueDestroy

        队列中的每一个结点所占用的内存空间都是动态开辟的,当我们使用完队列后需要及时释放队列中的每一个结点。

void QueueDestroy(Queue* pq) 
{// 断言检查传入的队列结构体指针是否有效assert(pq);// 创建一个临时指针 cur,初始化为队列的头节点QListNode* cur = pq->head;// 循环遍历队列中的每一个节点while (cur) {// 将 cur 的下一个节点赋值给临时指针 next,保存下一个节点的地址QListNode* next = cur->next;// 释放当前节点 cur 的内存free(cur);// 移动 cur 指针至下一个节点cur = next;}// 清空队列的头指针和尾指针,将它们都设置为 NULLpq->head = NULL;pq->tail = NULL;
}

        队尾入队列 QueuePush

        入队列,即申请一个新结点并将其链接到队尾,然后改变队尾的指针指向即可。需要注意的是:若队列中原本无数据,那么我们只需让队头和队尾均指向这个新申请的结点即可。

void QueuePush(Queue* pq, QDataType x) 
{// 断言检查队列结构体指针是否有效assert(pq);// 分配内存创建一个新的节点QListNode* newnode = (QListNode*)malloc(sizeof(QListNode));// 检查内存分配是否成功if (newnode == NULL) {// 若内存分配失败,输出错误信息并退出程序printf("malloc fail\n");exit(-1);}// 将新节点的数据域设置为要插入的元素值 xnewnode->data = x;// 新节点的下一节点指针初始化为 NULLnewnode->next = NULL;// 判断队列是否为空if (pq->head == NULL) {// 若队列为空,则新节点既是头节点也是尾节点pq->head = pq->tail = newnode;} else {// 若队列非空,将现有尾节点的下一节点指向新节点pq->tail->next = newnode;// 更新队列尾指针,使之指向新插入的节点pq->tail = newnode;}
}

        队头出队列 QueuePop

        出队列,即释放队头指针指向的结点并改变队头指针的指向即可。若队列中只有一个结点,那么直接将该结点释放,然后将队头和队尾置空即可。

void QueuePop(Queue* pq) 
{// 断言检查队列结构体指针是否有效assert(pq);// 断言检查队列是否为空,若为空则不能进行出队操作assert(!QueueEmpty(pq));// 判断队列中剩余元素数量if (pq->head->next == NULL) {// 如果队列只剩一个元素,则释放该元素,并将头尾指针都设为 NULLfree(pq->head);pq->head = NULL;pq->tail = NULL;} else {// 如果队列中还有多个元素,则释放头节点,然后将头指针指向下一个节点QListNode* next = pq->head->next;free(pq->head);pq->head = next;}
}

        获取队列头部元素 QueueFront

        获取队列头部元素,即返回队头指针指向的数据即可。

QDataType QueueFront(Queue* pq) 
{// 断言检查队列结构体指针是否有效assert(pq);// 断言检查队列是否为空,若为空则无法获取队头元素assert(!QueueEmpty(pq));// 返回队列头部节点(即队首元素)的数据域值return pq->head->data;
}

        获取队尾尾部元素

        获取队列尾部元素,即返回队尾指针指向的数据即可。

QDataType QueueBack(Queue* pq) 
{// 断言检查队列结构体指针是否有效assert(pq);// 断言检查队列是否为空,若为空则无法获取队尾元素assert(!QueueEmpty(pq));// 返回队列尾部节点(即队尾元素)的数据域值return pq->tail->data;
}

        检查队列是否为空 QueueEmpty

        检测队列是否为空,即判断队头指针指向的内容是否为空。

bool QueueEmpty(Queue* pq) 
{// 断言检查队列结构体指针是否有效assert(pq);// 判断队列是否为空的条件是:头指针(pq->head)是否为 NULL// 如果头指针为 NULL,则队列为空,返回 true// 否则,队列非空,返回 falsereturn pq->head == NULL;
}

        获取队列中有效元素个数 QueueSize

        队列中有效元素个数,即队列中的结点个数。我们只需遍历队列,统计队列中的结点数并返回即可。

int QueueSize(Queue* pq) 
{// 断言检查队列结构体指针是否有效assert(pq);// 初始化计数器 count 为 0int count = 0;// 创建一个临时指针 cur,初始化为队列的头节点QListNode* cur = pq->head;// 遍历队列,直到 cur 为空(即遍历完队列)while (cur) {// 计数器加一,表示找到了一个有效节点count++;// 将 cur 指针移向下一个节点cur = cur->next;}// 返回计数器 count 的值,即队列中有效元素的个数return count;
}

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

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

相关文章

建议收藏!网络安全入门知识汇总,自学必看!

计算机网络的广泛应用,为人们的生产、生活、工作、娱乐带来了方便,同时由于技术原因和人为因素,也为人们带来诸多安全隐患。这催发出一个新的职业——网络安全工程师。 目前网络安全工程师变得越来越重要,很多人也开始对网络安全…

jsp实验11 JavaBean

二、实验项目内容(实验题目) 编写代码,掌握javabean的用法。【参考课本 上机实验 5.5.2 】 三、源代码以及执行结果截图: 源代码: Memory.java package sea.water; import java.util.ArrayList; import java.util…

280 Stylized Desert Beach Textures - Sand Cracked Sand Water More v1.1.0

280多种风格化的沙子、破裂的沙子、土壤、沙质岩石和其他沙质纹理的集合,用于沙漠和海滩风格化/幻想/rpg风格的游戏环境。 这款由game Buffs设计的280多种风格化沙漠和海滩纹理系列,为您的游戏锦上添花! 在这个系列中,你会在风格化/幻想/rpg风格的游戏中找到大量适合沙漠、…

python与上位机开发day02

1.常见运算符 1.1 赋值运算符 赋值运算符主要用来对变量进行赋值,包括如下这些: 运算符描述赋值加等于-减等于*乘等于/除等于//整除等于%模等于**幂等于 实例如下: a 10 a 5 # 等价于 a a5 a *2 # 等价于 a a*21.2 比较运算符 比较运算符主要用来比较两个数据的大小…

树莓派驱动开发----iic驱动oled屏幕篇

水一期吧,上效果 有点模糊,我直接说吧,修改设备树,iic1,地址0x3c,然后编写驱动文件,app文件,挂载驱动模块后在终端输入 /*******************************************************…

Ventus(承影):基于RISC V的开源GPGPU

Ventus(承影):基于RVV的开源GPGPU 清华大学集成电路学院dsp-lab的承影RVV GPGPU设计文档。 整体目标 提供一个开源的基于RVV的GPGPU实现方案,并给出软件映射方案、指令集(支持的指令及特性、添加的自定义指令&#xf…

经典的目标检测算法有哪些?

一、经典的目标检测算法有哪些? 目标检测算法根据其处理流程可以分为两大类:One-Stage(单阶段)算法和Two-Stage(两阶段)算法。以下是一些经典的目标检测算法: 单阶段算法: YOLO (You Only Loo…

iOS ------代理 分类 拓展

代理协议 一,概念: 代理,又称委托代理(delegate),是iOS中常用的一种设计模式。顾名思义,它是把某个对象要做的事委托给别的对象去做。那么别的对象就是这个对象的代理,代替它来打理…

图书租赁系统-借阅图书

图中展示了所有可以借阅的图书&#xff0c;点击“借阅”按钮便可以借阅图书。 借阅成功后&#xff0c;可以到bookorder菜单中阅读该书。 阅读功能待开发。 add.html借阅图书页面 <!DOCTYPE html> <html lang"zh" xmlns:th"http://www.thymeleaf.org…

学习经验分享【33】YOLOv5 / YOLOv7 / YOLOv8 / YOLOv9 / RTDETR 基于 Pyside6 的图形化界面

大论文可以写两章关于算法创新模型&#xff0c;最后一章可以写对前两章提出方法进行封装&#xff0c;利用PyQT5搭建YOLOv5可视化界面&#xff0c;并打包成exe程序&#xff0c;构建检测平台实现简单的应用。用来凑大论文的字数和工作量&#xff0c;是简单又快速的方法&#xff0…

如何使用国内手机号免费注册一个美区 Apple ID?

因为一些众所周知的原因&#xff0c;在国内使用 iPhone 是被阉割过的&#xff0c;如果想要用完全版就需要用到美区账号&#xff0c;废话不多说直接上图。 在 iPhone 的浏览器上打开链接进行注册 https://appleid.apple.com/account 如果注册提示&#xff1a;Your request cou…

SpringCloud注册nacos错误:Could not resolvplaceholder ‘xxxxx‘ in value “xxxx“

这个错误是我在做spirngcloud注册服务到nacos时发现的&#xff0c;算是折磨我折磨了好久&#xff0c;最后发现了还是先记录一下&#xff0c;首先还是说一下我的项目版本信息&#xff0c;因为不同的版本就有这不同的解决方案&#xff0c;这也是最恶心的一点&#xff0c;以至于我…

基于RT-Thread的智能家居助手

一、项目简介 智能家居助手主要基于RT-Thread开发的&#xff0c;该系统主要分为语音子系统&#xff0c;环境监测子系统&#xff0c;智能控制子系统&#xff0c;智能网关子系统&#xff0c;音乐播放器&#xff0c;云端以及应用软件七大部分。语音子系统可通过语音进行人机交互来…

OpenCV——图像分块局部阈值二值化

目录 一、算法原理1、算法概述2、参考文献 二、代码实现三、结果展示 OpenCV——图像分块局部阈值二值化由CSDN点云侠原创&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫。 一、算法原理 1、算法概述 针对目前局部阈值二值…

from_pretrained明明以及下载好模型,却突然不能加载了报错

本人报错&#xff1a;OSError: Error no file named model_index.json found in directory /home/xxx/我的python学习/textToImage/sdxl-turbo. 原因&#xff1a;路径错误导致无法加载模型的配置文件 pipe AutoPipelineForText2Image.from_pretrained("stabilityai/sdx…

HORROR SYSTEM

HORROR SYSTEM是一个创新的工具包,允许开发者在Unity3D中创建独特的原创恐怖游戏。 HORROR SYSTEM是一款强大而灵活的工具,旨在基于Unity3D引擎创建沉浸式第三人称恐怖游戏。 这项资产易于使用且直观,可以让任何经验水平的开发人员将他们的想法付诸实践,创造出高质量、充满…

文献速递:深度学习胶质瘤诊断---空间细胞结构预测胶质母细胞瘤的预后

Title 题目 Spatial cellular architecture predicts prognosis in glioblastoma 空间细胞结构预测胶质母细胞瘤的预后 01文献速递介绍 胶质母细胞瘤的治疗耐药性的关键驱动因素是肿瘤内的异质性和细胞状态的可塑性。在这里&#xff0c;我们调查了空间细胞组织与胶质母细胞瘤…

python爬虫 - 爬取html中的script数据(zum.com新闻信息 )

文章目录 1. 分析页面内容数据格式2. 使用re.findall方法&#xff0c;编写爬虫代码3. 使用re.search 方法&#xff0c;编写爬虫代码 1. 分析页面内容数据格式 &#xff08;1&#xff09;打开 https://zum.com/ &#xff08;2&#xff09;按F12&#xff08;或 在网页上右键 --…

C++中的五种高级初始化技术:从reserve到piecewise_construct等

C高级初始化技术&#xff1a;reserve、emplace_back、constinit、Lambda表达式、piecewise_construct 一、简介二、reserve 结合 emplace_back三、C 20的constinit四、Lambda表达式和初始化五、make_unique_for_overwrite六、piecewise_construct 和 forward_as_tuple七、总结 …

SpringBoot xxl-job 任务调度

首先官网下载xxl-job的源代码&#xff0c;然后切换到jdk8&#xff0c;等Maven下载依赖 执行mysql的脚本&#xff0c;修改连接配置&#xff0c;启动admin站点 默认地址 http://localhost:8080/xxl-job-admin/ 先新增一个任务执行器&#xff0c;指向未来任务代码的站点 然后在…