【数据结构】线性表之《队列》超详细实现

队列

  • 一.队列的概念及结构
  • 二.顺序队列与链队列
    • 1.顺序队列
    • 2.链队列
  • 三.链队列的实现
    • 1.创建队列
    • 2.初始化队列
    • 3.入队
    • 4.出队
    • 5.获取队头元素
    • 6.获取队尾元素
    • 7.队列的大小
    • 8.队列的判空
    • 9.清空队列
    • 10.销毁队列
  • 四.队列的盲区
  • 五.模块化源代码
    • 1.Queue.h
    • 2.Queue.c
    • 3.test.c
  • 六.栈和队列必做OJ题

一.队列的概念及结构

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

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

在这里插入图片描述

二.顺序队列与链队列

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

在这里插入图片描述

1.顺序队列

在这里插入图片描述

2.链队列

在这里插入图片描述

那是不是再用一个指针指向队尾就可以了呢?是的如下图:

在这里插入图片描述

这种链表结构完美的解决了尾插时效率低的问题。

三.链队列的实现

1.创建队列

先创建结构体(存放数据和先一个节点的地址)用来表示节点,再额外创建队列结构体(成员:队头指针和队尾指针),队头指针指向队列的队头,队尾指针指向队列的队尾。

typedef int QDataType;typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;
}Queue;Queue q;//q代表链队列

2.初始化队列

将队头指针和队尾指针初始化为NULL。

void QueueInit(Queue* pq)
{assert(pq);//断言pq->head = pq->tail = NULL;
}

3.入队

先是创建一个新的节点,存放数据和NULL指针,入队分两种情况:

  1. 若队头和队尾指针都为NULL,则队头和队尾指针都指向新的节点。
  2. 若队头和队尾指针不为NULL,则向队尾插入新的节点,再更新队尾指针。
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//创建入队的节点QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL)//开辟失败{perror("malloc fail!");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;}
}

4.出队

出队也有两种情况

  1. 队列只有一个节点,先删除队头,再让队头和队尾指针指向NULL,防止队尾指针变成野指针。
  2. 队列有多个节点,先保存队头的下一个节点指针,再删除队头,最后更新队头指针。
void QueuePop(Queue* pq)
{assert(pq);assert(pq->head != NULL);//队列不能为空//队列只有一个节点if (pq->tail->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}//队列有多个节点else{QNode* next = pq->head->next;free(pq->head);pq->head = next;}
}

5.获取队头元素

QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->head != NULL);//队列不能为空return pq->head->data;
}

6.获取队尾元素

QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->tail != NULL);//队列不能为空return pq->tail->data;
}

7.队列的大小

定位队头节点,利用NULL这一条件遍历队列即可。

int QueueSize(Queue* pq)
{assert(pq);QNode* cur = pq->head;//定位队头节点int size = 0;while (cur != NULL){size++;cur = cur->next;//更新cur}return size;
}

8.队列的判空

判断队头指针是否为NULL即可。

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}

9.清空队列

定位队头节点,依次先后删除即可。

void QueueClear(Queue* pq)
{assert(pq);QNode* cur = pq->head;//定位队头节点while (cur != NULL){QNode* next = cur->next;free(cur);//逐个删除cur = next;}pq->head = pq->tail = NULL;
}

10.销毁队列

void QueueDestory(Queue* pq)
{assert(pq);QueueClear(pq);//注意不能释放pq,这不是动态开辟的地址,而是栈区的地址,所以清空与销毁没什么区别
}

四.队列的盲区

由于队列的特殊结构,只能遵循先进先出的原则,不允许随便遍历队列,否则就失去了队列的特点,只能用以下的代码得到数据:

while (!QueueEmpty(&q))
{printf("%d ", QueueFront(&q));QueuePop(&q);
}

五.模块化源代码

1.Queue.h

//#pragma once 防止头文件被重复包含
#ifndef __QUEUE_H__
#define __QUEUE_H__#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int QDataType;typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;
}Queue;void QueueInit(Queue* pq);//初始化队列void QueuePush(Queue* pq, QDataType x);//入队void QueuePop(Queue* pq);//出队QDataType QueueFront(Queue* pq);//获取队头元素QDataType QueueBack(Queue* pq);//获取队尾元素int QueueSize(Queue* pq);//队列大小bool QueueEmpty(Queue* pq);//队列判空void QueueClear(Queue* pq);//清空队列void QueueDestory(Queue* pq);//销毁队列
#endif

2.Queue.c

#define _CRT_SECURE_NO_WARNINGS 1#include"Queue.h"void QueueInit(Queue* pq)
{assert(pq);//断言pq->head = pq->tail = NULL;
}void QueuePush(Queue* pq, QDataType x)
{assert(pq);//创建入队的节点QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL)//开辟失败{perror("malloc fail!");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;}
}void QueuePop(Queue* pq)
{assert(pq);assert(pq->head != NULL);//队列不能为空//队列只有一个节点if (pq->tail->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}//队列有多个节点else{QNode* next = pq->head->next;free(pq->head);pq->head = next;}
}QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->head != NULL);//队列不能为空return pq->head->data;
}QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->tail != NULL);//队列不能为空return pq->tail->data;
}int QueueSize(Queue* pq)
{assert(pq);QNode* cur = pq->head;//定位队头节点int size = 0;while (cur != NULL){size++;cur = cur->next;//更新cur}return size;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}void QueueClear(Queue* pq)
{assert(pq);QNode* cur = pq->head;//定位队头节点while (cur != NULL){QNode* next = cur->next;free(cur);//逐个删除cur = next;}pq->head = pq->tail = NULL;
}void QueueDestory(Queue* pq)
{assert(pq);QueueClear(pq);//注意不能释放pq,这不是动态开辟的地址,而是栈区的地址,所以清空与销毁没什么区别
}

3.test.c

#define _CRT_SECURE_NO_WARNINGS 1#include"Queue.h"enum //匿名枚举
{EXIT,PUSH,POP,FRONT,BACK,SIZE,EMPTY,CLEAR
};void Menu()
{printf("*************队列*************\n");printf("****1.入队          2.出队****\n");printf("****3.队头          4.队尾****\n");printf("****5.大小          6.判空****\n");printf("****7.清空          0.退出****\n");printf("******************************\n");
}int main()
{Queue q;QueueInit(&q);int select = 0;bool flag;QDataType value;do{Menu();printf("请选择您的操作:");scanf("%d", &select);switch (select){case EXIT:printf("退出队列!\n");break;case PUSH:printf("请输入您要入队的值:");scanf("%d", &value);QueuePush(&q, value);break;case POP:QueuePop(&q);break;case FRONT:value = QueueFront(&q);printf("队头元素值为:%d\n", value);break;case BACK:value = QueueBack(&q);printf("队尾元素值为:%d\n", value);break;case SIZE:printf("队列的大小为:%d\n", QueueSize(&q));break;case EMPTY:flag = QueueEmpty(&q);if (flag){printf("队列为空!\n");}else{printf("队列不为空!\n");}break;case CLEAR:QueueClear(&q);break;default:printf("输入错误,请重新输入!\n");break;}} while (select);QueueDestory(&q);return 0;
}

六.栈和队列必做OJ题

  1. 括号匹配问题
  2. 用队列实现栈
  3. 用栈实现队列

创作不易,如果能帮到你的话能赏个三连吗?感谢啦!!!

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

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

相关文章

unity-调用讯飞星火语音唤醒-新版windowsSDK

调用讯飞星火语音唤醒-新版windowsSDK 先贴一张在unity中 wins系统下成功调用新版的讯飞windowsSDK的运行截图 为什么要用讯飞的语音唤醒&#xff1f; 项目中需要在unity和win系统下进行语音唤醒开启语音对话&#xff0c;而语音唤醒比较成熟的方案大多都是在linux系统下的&…

kafka 生产者 API 实践总结

文章目录 前言创建 kafka 生产者同步与异步发送消息同步发送异步发送 生产者参数配置client.idacks消息传递时间 序列化器在Kafka中使用Avro记录 分区标头拦截器配额和节流 前言 kafka 对外提供的 API 主要有两类&#xff1a;生产者 API 和 消费者 API&#xff0c;本文将从Kaf…

Spring中事务的传播机制

一、前言 首先事务传播机制解决了什么问题 Spring 事务传播机制是包含多个事务的方法在相互调用时&#xff0c;事务是如何在这些方法间传播的。 事务的传播级别有 7 个&#xff0c;支持当前事务的&#xff1a;REQUIRED、SUPPORTS、MANDATORY&#xff1b; 不支持当前事务的&…

[Django学习]前端+后端两种方式处理图片流数据

方式1&#xff1a;数据库存放图片地址,图片存放在Django项目文件中 1.首先&#xff0c;我们现在models.py文件中定义模型来存放该图片数据,前端传来的数据都会存放在Django项目文件里的images文件夹下 from django.db import modelsclass Image(models.Model):title models.C…

幻兽帕鲁更新时间 幻兽帕鲁最新更新内容一览

超级缝合怪游戏幻兽帕鲁相信大家都有所了解了&#xff0c;游戏刚出的时候也是引起很大的轰动&#xff0c;吸引了很多玩家&#xff0c;一度登上steam榜首&#xff0c;游戏借鉴了“全球最赚钱IP”任天堂宝可梦的收集神奇生物系统&#xff0c;缝合到更多开放世界游戏玩法里&#x…

【背包题解】DP代表了走到阶段i 的所有路线的最优解

1889:【提高】多重背包(2) 二维费用背包 2075 - 最大卡路里 1928 - 采购礼品 感谢 背包容量&#xff1a;&#xff08;c&#xff09; 6 重量 weight 2 2 4 6 2 1 2 3 4 5 价值 value 3 6 5 5 8 1 2 3 4 5 wvdp数组&#xff1a;记录有i件…

使用 GitOps 进行防灾 MinIO

想象一下&#xff0c;您已经花费了无数小时来完善 Docker Swarm 设置&#xff0c;精心设计每项服务&#xff0c;并调整 CI/CD 管道以实现无缝自动化。现在&#xff0c;想象一下这个经过微调的系统被重置为原点&#xff0c;不是因为严重的故障或安全漏洞&#xff0c;而是因为数据…

Python开发日记--手撸加解密小工具(2)

目录 1. UI设计和代码生成 2.运行代码查看效果 3.小结 1. UI设计和代码生成 昨天讨论到每一类算法设计为一个Tab&#xff0c;利用的是TabWidget&#xff0c;那么接下来就要在每个Tab里设计算法必要的参数了&#xff0c;这里我们会用到组件有Label、PushButton、TextEdit、Ra…

【算法】数组-基础知识与应用

一.基础理论 数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标对应的数据。 数组下标都是从0开始的。数组内存空间的地址是连续的 因为数组在内存空间的地址是连续的&#xff0c;所以我们在删除或者增添元素的时候&#xff0c…

【华为HCIA数通网络工程师真题-构建以太网交换网络】

华为HCIA数通网络工程师真题-构建以太网交换网络 一、1-10题 一、1-10题 1、如图所示&#xff0c;四台交换机都运行 STP&#xff0c;各种参数都采用默认值如果交换机C的G0/0/2端口发生阻塞并无法通过该端口发送配置 BPDU&#xff0c;则网络中 blocked 端口多久之后会进入到转发…

【数据结构与算法】动态查找表(二叉排序树,二叉平衡树)详解

二叉排序树的数据结构。 struct TreeNode {ElemType data;TreeNode *left, *right; }; using BiTree TreeNode *;结构体包含三个成员&#xff1a; data 是一个 ElemType 类型的变量&#xff0c;用于存储二叉搜索树节点的数据。left 是一个指向 TreeNode 类型的指针&#xff…

动态规划数字三角形模型——AcWing 1015. 摘花生

动态规划数字三角形模型 定义 动态规划数字三角形模型是在一个三角形的数阵中&#xff0c;通过一定规则找到从顶部到底部的最优路径或最优值。 运用情况 通常用于解决具有递推关系、需要在不同路径中做出选择以达到最优结果的问题。比如计算最短路径、最大和等 注意事项 …

【SAP HANA 35】HANA窗口函数PARTITION BY示例

窗口函数允许对数据进行高级分析和计算&#xff0c;例如排名和累计和。 -- 计算每个员工在其职位组中的工资排名 SELECTFirstName,LastName,Position,Salary,RANK() OVER (PARTITION BY FirstName,LastName ORDER BY Salary DESC) AS Rank FROM Employees;-- 计算每个员工在其…

机器学习-线性回归模型python demo

文章目录 前言机器学习-线性回归模型python demo1. 准备工作2. 实施2.1. 准备样本数据2.2. 创建线性回归模型2.3. 预测新的房价 3. 散点图、线形图 完整demo 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不…

【Python】已解决:Python读取字典查询键报错“KeyError: ‘d‘”

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;Python读取字典查询键报错“KeyError: ‘d’” 一、分析问题背景 在Python编程中&#xff0c;字典&#xff08;dictionary&#xff09;是一种非常重要的数据结构…

静态内部类局部内部类

静态内部类 创建静态内部类对象的格式&#xff1a;外部类名.内部类名 对象名new外部类名.内部类名&#xff08;&#xff09;; 调用非静态方法的格式&#xff1a;先创建对象&#xff0c;用对象调用 调用静态方法的格式&#xff1a;外部类名.内部类名.方法名&#xff08;&#…

GMSB文章一:介绍

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 Lin, Huang, et al. [lin2024effect]&#xff0c;本文的研究重点是探讨性行为对HIV-1血清转换的影…

【笔记】echarts图表的缩放和鼠标滚动的处理解决方案

解决方案不是很好&#xff0c;来源于github的issue&#xff0c;官方提供了&#xff0c;组合键触发缩放的功能。 https://github.com/apache/echarts/issues/5769 https://echarts.apache.org/zh/option.html#dataZoom-inside.zoomOnMouseWheel dataZoom-inside.zoomOnMouseWhe…

面试-细聊synchronized

1.线程安全问题的主要诱因&#xff1a; 存在多条共享数据(临界资源) 存在多条线程共同操作这些共享数据 解决问题的根本方法&#xff1a; 同一时刻有且仅有一个线程在操作共享数据&#xff0c;其他线程必须等到该线程处理完数据后在对共享数据进行操作。 2.synchroized锁 分…

C++三大特性之一:多态

一、多态 1、通过指针创建对象&#xff08;动态分配&#xff09; #include <iostream> using namespace std;class Base { public:virtual void show() {cout << "Base class show" << endl;} };class Derived : public Base { public:void show…