当前位置: 首页 > web >正文

【数据结构初阶】--栈和队列(二)

🔥个人主页:@草莓熊Lotso

🎬作者简介:C++研发方向学习者

📖个人专栏: 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》

⭐️人生格言:生活是默默的坚持,毅力是永久的享受。

前言: 在上篇博客中我们简单完成了栈这个数据结构的实现,那么这次我们要实现的是队列,队列这个数据结构实现起来也不会很难,还是和之前一样,先部分实现,最后展现全部的代码 


目录

一.队列的概念与结构

二. 队列的入队和出队

入队:

 出队:

 三.队列取队首数据和队尾数据

取队首数据:

取队尾数据 :

 四.队列的有效数据个数和队列的销毁

队列的有效数据个数:

销毁队列:

五.代码展现

Queue.h:

Queue.c:

test.c:


一.队列的概念与结构

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

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

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

 队列底层结构选型:

队列可以用数组和链表的结构实现,使用链表的结构实现更优一点,如果使用数组的结构,出队列在数组头部出数据,时间复杂度高。虽然使用链表在入队尾插的时候,时间复杂度也高,但我们可以额外定义一个尾结点,这样就可以优化了

结构定义: 

typedef int QDataType;
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QueueNode;typedef struct Queue
{QueueNode* phead;QueueNode* ptail;//int size;//队中有效数据个数
}Queue;

二. 队列的入队和出队

--我们实现队列的入队是在队尾操作的,所以我们可以参考链表的尾插,但是这里我们已经定义了一个尾节点了,所以会更简单点

入队:

//入队
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//申请新节点QueueNode* newcode = (QueueNode*)malloc(sizeof(QueueNode));if (newcode == NULL){perror("malloc fail!");exit(1);}newcode->data = x;newcode->next = NULL;//如果队列为空if (pq->phead == NULL){pq->phead = pq->ptail = newcode;//pq->size++;}else{pq->ptail->next = newcode;pq->ptail = pq->ptail->next;//pq->size++;}
}

我们入队之前,需要申请一个新的节点,操作起来和链表里面的一样,申请完后先判断链表是不是为空,为空和不为空需要分类讨论,如果为空就直接令头节点和尾节点都为newcode,如果不为空就是在尾节点后链接上新节点,然后尾节点往前走。 

 --在实现出队之前,我们需要考虑到一个队列为空的问题,如果队列为空是不是就不能删了呢,所以我们这里来实现一个判断链表是否为空的接口吧,这个实现起来很简单,就不多说了

//队列判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}

 出队:

//出队
void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));//如果队伍中只有一个节点if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;//pq->size--||pq->size=0}else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;//pq->size--;}
}

我们需要注意的是断言结束后,如果队伍只有一个节点,我们直接释放掉后使置为空就行了,如果不止一个节点我们需要先记录下一个节点,再释放,然后让头节点来到下一个节点的位置。


 三.队列取队首数据和队尾数据

取队首数据:

//取队首数据
QDataType QueueHead(Queue* pq)
{assert(!QueueEmpty(pq));return pq->phead->data;
}

队首数据不就是头节点的数据吗,直接返回就好了

取队尾数据 :

//取队尾数据
QDataType QueueTail(Queue* pq)
{assert(!QueueEmpty(pq));return pq->ptail->data;
}

队尾数据不就是头节点的数据吗,直接返回就好了

--实现完前面的接口之后我们可以测试一下看看

 test.c:

#include"Queue.h"void test1()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);printf("队首是:%d\n",QueueHead(&q));printf("队尾是:%d\n",QueueTail(&q));
}int main()
{test1();
}

--测试完成,打印出了队尾和队首数据,退出码为0


 四.队列的有效数据个数和队列的销毁

队列的有效数据个数:

//队列有效数据个数
int QueueSize(Queue* pq)
{//如果使用了size记录直接返回就可以了//return pq->size;//如果没有就遍历QueueNode* pcur = pq->phead;int size = 0;while (pcur){++size;pcur=pcur->next;}return size;
}

这里给大家提供了两种写法,一个是前面定义了size的,一个是没有定义过的,没有定义的我们需要遍历计数,最后再返回就行了。 

销毁队列:

//队列的销毁
void QueueDestory(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;
}

遍历队列,每次销毁前存下下一个节点,销毁当前节点后来到下一个节点的位置,最后遍历结束后把pq->phead和pq->ptail都置为空

--这里也可以通过测试文件打印观察数据个数,就不在这里展示了,大家可以直接看一下代码展现里面 


五.代码展现

Queue.h:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int QDataType;
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QueueNode;typedef struct Queue
{QueueNode* phead;QueueNode* ptail;//int size;//队中有效数据个数
}Queue;//队列的初始化
void QueueInit(Queue* pq);//入队
void QueuePush(Queue* pq, QDataType x);//队列判空
bool QueueEmpty(Queue* pq);//出队
void QueuePop(Queue* pq);//取队首数据
QDataType QueueHead(Queue* pq);//取队尾数据
QDataType QueueTail(Queue* pq);//队列有效数据个数
int QueueSize(Queue* pq);//队列的销毁
void QueueDestory(Queue* pq);

Queue.c:

#include"Queue.h"//队列的初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;//pq->size = 0;
}//入队
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//申请新节点QueueNode* newcode = (QueueNode*)malloc(sizeof(QueueNode));if (newcode == NULL){perror("malloc fail!");exit(1);}newcode->data = x;newcode->next = NULL;//如果队列为空if (pq->phead == NULL){pq->phead = pq->ptail = newcode;//pq->size++;}else{pq->ptail->next = newcode;pq->ptail = pq->ptail->next;//pq->size++;}
}//队列判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}//出队
void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));//如果队伍中只有一个节点if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;//pq->size--||pq->size=0}else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;//pq->size--;}
}//取队首数据
QDataType QueueHead(Queue* pq)
{assert(!QueueEmpty(pq));return pq->phead->data;
}//取队尾数据
QDataType QueueTail(Queue* pq)
{assert(!QueueEmpty(pq));return pq->ptail->data;
}//队列有效数据个数
int QueueSize(Queue* pq)
{//如果使用了size记录直接返回就可以了//return pq->size;//如果没有就遍历QueueNode* pcur = pq->phead;int size = 0;while (pcur){++size;pcur=pcur->next;}return size;
}//队列的销毁
void QueueDestory(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;
}

test.c:

#include"Queue.h"void test1()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);printf("队首是:%d\n",QueueHead(&q));printf("队尾是:%d\n",QueueTail(&q));printf("size:%d\n", QueueSize(&q));QueueDestory(&q);
}int main()
{test1();
}


往期回顾:

【数据结构初阶】--双向链表(一)

【数据结构初阶】--双向链表(二)

【数据结构初阶】--栈和队列(一)

结语:队列的实现就到此结束了,栈和队列这块的知识点和实现起来都比较快,但是后面的二叉树的难度就上来了,大家一定要先把前面这些搞懂并且实现出来,不然后续会比较吃力的,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持

http://www.xdnf.cn/news/16112.html

相关文章:

  • Python之格式化Conda中生成的requirements.txt
  • 我的第一个开源项目 -- 实时语音识别工具
  • 数据库表介绍
  • 算法提升之字符串回文处理-(manacher)
  • 自编码器表征学习:重构误差与隐空间拓扑结构的深度解析
  • 客户案例 | Jabil 整合 IT 与运营,大规模转型制造流程
  • 《小白学习产品经理》第八章:方法论之马斯洛需求层次理论
  • Java新特性-record
  • 力扣-139.单词拆分
  • js的基本内容:引用、变量、打印、交互、定时器、demo操作
  • 网络安全基础作业三
  • lspci/setpci用法小结
  • SpringBoot--Mapper XML 和 Mapper 接口在不同包
  • halcon手眼标定z方向实操矫正
  • [2025CVPR]ViKIENet:通过虚拟密钥实例增强网络实现高效的 3D 对象检测
  • React 项目性能优化概要
  • vs2017 c++ 使用sqlite3数据库
  • 基于Kubernetes的微服务CI/CD:Jenkins Pipeline全流程实践
  • 如何编译RustDesk(Unbuntu 和Android版本)
  • MongoDB数据库详解-针对大型分布式项目采用的原因以及基础原理和发展-卓伊凡|贝贝|莉莉
  • haproxy的负载均衡集群搭建
  • Rust实战:决策树与随机森林实现
  • 微博视觉算法面试30问全景精解
  • MDC(Mapped Diagnostic Context) 的核心介绍与使用教程
  • 【PTA数据结构 | C语言版】爱之匹配
  • 【C++】继承和多态扩展学习
  • 【上市公司变量测量】Python+FactSet Revere全球供应链数据库,测度供应链断裂与重构变量——丁浩员等(2024)《经济研究》复现
  • Docker从入门到精通
  • IPv4枯竭时代:从NAT技术到IPv6的演进之路
  • SpringBoot6-10(黑马)