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

队列

  • 一.队列的概念及结构
  • 二.顺序队列与链队列
    • 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.rhkb.cn/news/360130.html

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

相关文章

FlinkCDC介绍及使用

CDC简介 什么是CDC&#xff1f; cdc是Change Data Capture(变更数据获取)的简称。核心思想是&#xff0c;监测并捕获数据库的 变动(包括数据或数据表的插入&#xff0c;更新以及删除等)&#xff0c;将这些变更按发生的顺序完整记录下来&#xff0c;写入到消息中间件以供其它服…

Flutter 像素编辑器#05 | 缩放与平移

theme: cyanosis 本系列&#xff0c;将通过 Flutter 实现一个全平台的像素编辑器应用。源码见开源项目 【pix_editor】。在前三篇中&#xff0c;我们已经完成了一个简易的图像编辑器&#xff0c;并且简单引入了图层的概念&#xff0c;支持切换图层显示不同的像素画面。 《Flutt…

【工具测评】ONLYOFFICE——你的下一款桌面编辑器

文章目录 前言一、安装1.1 跳转官网下载安装包1.2 安装步骤 二、功能介绍2.1 功能全面的 PDF 编辑器2.2 PDF 表单2.3 文本文档编辑器的更新2.4 电子表格编辑器的更新2.5 演示文稿编辑器有哪些更新2.6 所有编辑器中的改进内容2.7 从右至左显示 & 新的本地化选项2.8 可用性提…

基于Java超市库存管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

10.2 JavaEE——Spring MVC入门程序

要求在浏览器发起请求&#xff0c;由Spring MVC接收请求并响应&#xff0c;具体实现步骤如下。 一、创建项目 在IDEA中&#xff0c;创建一个名称为chapter10的Maven Web项目。 &#xff08;一&#xff09;手动设置webapp文件夹 1、单击IDEA工具栏中的File→“Project Structu…

学校校园考场电子钟,同步授时,助力考场公平公正-讯鹏科技

随着教育技术的不断发展&#xff0c;学校对于考场管理的需求也日益提高。传统的考场时钟往往存在时间误差、维护不便等问题&#xff0c;这在一定程度上影响了考试的公平性和公正性。为了解决这些问题&#xff0c;越来越多的学校开始引入考场电子钟&#xff0c;通过同步授时技术…

Nginx实现动静分离

目录 静态资源 动态资源 区别和应用场景 1. 准备环境 2. 配置代理 3. 静态资源主机配置 4. 动态资源主机配置 5. 访问静态和动态资源测试 测试1&#xff1a;访问静态资源 测试2&#xff1a;访问动态资源 动态资源和静态资源是在网络和Web开发中常用的两个概念&#…

「全新升级,性能更强大——ONLYOFFICE 桌面编辑器 8.1 深度评测」

文章目录 一、背景二、界面设计与用户体验三、主要新功能亮点3.1 高效协作处理3.2 共同编辑&#xff0c;毫无压力3.3 批注与提及3.4 追踪更改3.5 比较与合并3.6 管理版本历史 四、性能表现4.1 集成 AI 工具4.2 插件强化 五、用户反馈与使用案例 一、背景 Ascensio System SIA -…

48、基于深度学习的离群值输入向量(matlab)

1、基于深度学习的离群值输入向量原理及流程 基于深度学习的离群值检测的输入向量原理是通过神经网络模型对数据进行学习和表示&#xff0c;在该表示中探测异常样本。其流程大致如下&#xff1a; 数据预处理&#xff1a;将数据进行归一化处理&#xff0c;确保神经网络模型能够…

Java Scanner 类

Java Scanner 类 java.util.Scanner 是 Java5 的新特征&#xff0c;我们可以通过 Scanner 类来获取用户的输入。 下面是创建 Scanner 对象的基本语法&#xff1a; Scanner s new Scanner(System.in);接下来我们演示一个最简单的数据输入&#xff0c;并通过 Scanner 类的 nex…

如何评估LabVIEW需求中功能的必要性和可行性

评估LabVIEW需求中功能的必要性和可行性涉及多个方面的分析&#xff0c;包括需求的重要性、技术可行性、资源需求以及潜在风险。以下是一个详细的评估方法&#xff1a; ​ 一、功能必要性评估 需求来源和目的&#xff1a; 来源&#xff1a;需求来自哪里&#xff1f;是客户、市…

Windows系统下安装RabbitMQ详细步骤

声明&#xff1a;原文参考链接出自&#xff1a; 如何在Windows系统下安装RabbitMQ_rabbitmq windows安装-CSDN博客 https://zhuanlan.zhihu.com/p/693160757 一、RabbitMQ安装软件资源准备 因为RabbitMQ是Erlang语言开发的&#xff0c;因此安装Erlang环境在进行安装RbbitMQ的…

贺尔碧格流量阀比例放大器PSR2BE10P25、PSR2BE10P30、PSR2BE10P25

PSR2BE04N06、PSR2BE04P10、PSR2BE04P06、PSR2BE04N10、PSR2BE10N12、PSR2BE10P25、PSR2BE10P30、PSR2BE10P25、PSR3BE10N25、PSR3BE10P30、PSR3BE10P12贺尔碧格HOERBIGER液压比例流量阀由比例电磁铁和流量阀组合而成&#xff0c;利用输入的电信号来改变节流阀的开度&#xff0…

深入解析 iOS 应用启动过程:main() 函数前的四大步骤

深入解析 iOS 应用启动过程&#xff1a;main() 函数前的四大步骤 背景描述&#xff1a;使用 Objective-C 开发的 iOS 或者 MacOS 应用 在开发 iOS 应用时&#xff0c;我们通常会关注 main() 函数及其之后的执行逻辑&#xff0c;但在 main() 函数之前&#xff0c;系统已经为我们…

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

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

SiLM5350系列SiLM5350SABCA-DG 10A30V提供分离输出 单通道隔离栅极驱动器

SiLM5350系列SiLM5350SABCA-DG是具体有10A峰值输出电流能力&#xff0c;单通道隔离式栅极驱动器。SiLM5350系列SiLM5350SABCA-DG提供分离输出&#xff0c;可分别控制上升和下降时间。驱动电源电压为4V至30V。3V至18V的宽输入VDDI范围使驱动器适合与模拟和数字控制器接口。所有电…

c++网络通信

TCP/IP协议 OSI参考模型采用分层划分原则&#xff0c;将网络中的数据传输划分为7层&#xff0c;其中&#xff0c;物理层居于最下层&#xff0c;是最基础、核心的网络硬件层&#xff1b;应用层居于最上层&#xff0c;负责应用资源的管理。每一层使用下层的服务&#xff0c;并向…

Python爬取中国福彩网彩票数据并以图表形式显示

网页分析 首先打开中国福彩网&#xff0c;点击双色球&#xff0c;选择往期开奖栏目 进入栏目后&#xff0c;选定往期的奖金数目作为我们想要爬取的目标内容 明确目标后&#xff0c;开始寻找数据所在的位置 鼠标右击页面&#xff0c;打开网页源代码&#xff0c;在源代码中搜索…

<Rust><iced>在iced中显示gif动态图片的一种方法

前言 本文是在rust的GUI库iced中在窗口显示动态图片GIF格式图片的一种方法。 环境配置 系统&#xff1a;window 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;iced、image 概述 在iced中&#xff0c;提供了image部件&#xff0c;从理论上说&…

手机删除照片后还可以恢复吗?5个步骤,教你掌握正确方法

手机里的照片是我们记录生活、珍藏回忆的宝库&#xff0c;但有时候我们可能会不小心删除照片&#xff0c;或者因为各种原因需要恢复已经删除的照片。别担心&#xff0c;这篇文章将为你提供关于手机照片恢复的全面指南&#xff0c;揭开手机照片的恢复之谜&#xff0c;重新拥有那…