数据结构——队列的讲解(超详细)

news2025/1/10 6:10:01

前言:

  我们在之前刚讲述完对于栈的讲解,下面我们在讲另一个类似栈的数据结构——队列,它们都是线性表,但结构是大有不同,下面我们直接进入讲解!

701143ba8e234b1b958c187f409cf67b.png


目录

1.队列的概念和结构

 1.1.队列的概念

 1.2.队列的结构

2.队列的实现 (基于单链表实现)

 2.1. 队列的初始化

 2.2.入队列(尾插)

 2.3.出队列

 2.4.获取队头元素

 2.5.获取队尾元素

 2.6.队列中有效元素的个数

 2.7.队列的销毁

3.代码展示 

 3.1.Queue.h

 3.2.Queue.c

总结


 

正文:

1.队列的概念和结构

 1.1.队列的概念

  队列和栈一样也是一种线性表,只不过队列和栈是不同的,队列是从一端进入,从另一端出,就有先进先出FIFO的特点,小编之前讲过的栈,是有后进先出的特点,这就是这俩之间的不同之处。下面我们开始讲解队列的结构。

 1.2.队列的结构

b6cd910db1dc40c6b2e60e7e1ba96bd4.png

  如上图所示,队列中,插入数据的那一端,叫做队尾,删除数据的那一端叫做队头,所以队列是两头类型的结构,而栈就是一头(毕竟只可以从一头插入删除数据),以上就是队列的概念和结构,除了这些,我们更要会队列的书写 ,下面小编将要带领大家去学习队列的实现!

8599fa2455d145ccb90d8aa1d6649dcc.jpeg

2.队列的实现 (基于单链表实现)

  首先,队列和栈一样,它们都有两种实现方式,栈的时候我们选择了底层是顺序表的方式,因为栈涉及到了尾插,所以顺序表的时间复杂度比较小,但是队列不一样,队列因为是尾插头删,所以小编在本篇文章中的队列是用链表(单链表)来实现的,当然,队列也可以用顺序包实现,后面小编会在习题的分享上来告诉各位如何创建的,那么下面正式开启我们的代码之旅~下面是队列所对应的结构体,其中我们要设置一个单链表的结点从而方便表示队列的数据,然后我们为了减小时间复杂度,所以特地的表示出了头结点和尾结点(后期会说为什么这么设置),然后用size表示队列中有效元素的个数:

typedef int QDataType;
typedef struct list {                //表示单链表
	QDataType data;
	struct list* next;
}list;


typedef struct Queue {   //队列对应的结构体
	list* phead;
	list* plist;
	int size;   //表示队列有效的个数
}Queue;

 2.1. 队列的初始化

  对于队列我们首先肯定还要初始化,它的初始化还是比较简单的,就把头结点和尾结点都智为空就好,然后让队列有效元素个数为0就好了。由于难度不大,下面小编直接展示代码了:

void QueueInit(Queue* pq)
{
	pq->phead = pq->plist = NULL;
	pq->size = 0;
}

 2.2.入队列(尾插)

  我们先不讲队列的销毁,它是有一点复杂的,所以小编先讲别的,我们想讲述数据如何进入队列,这时候就用上了尾插操作,因为数据是从队伍的尾进的,对于插入结点,小编在之前就说过,此时的我们需要设置一个函数,这个函数是用来创建新结点的,对于新节点的创建小编在单链表说过,但现在小编还是多说一句吧,对于新结点的创建我们可以使用动态内存函数来创建一个新的节点,然后让新节点存放的数据变成0,下一个节点变成空,然后我们返回这个结点就好了,下面小编上代码了:

list* Queuebuynode(QDataType x)    //创建新结点的函数
{
	list* p1 = (list*)malloc(sizeof(list));
	assert(p1);
	p1->next = NULL;
	p1->data = x;
	return p1;  //别忘记返回,这个的类型是链表类型
}

  之后我们需要分为两种情况判断,如果队列中的队头为空,那么我们可以直接把新节点传给队头队尾,如果不为空的话,那么我们可以直接让队尾的下一个数据为新节点,让队尾的下一个节点在变成队尾,与当初小编写的单链表尾插差不多,不过小编当初写单链表可是没有创建链表尾,当时是用了循环才找到最后一个结点,所以我们在队列中设置队尾,是为了不在循环,减小时间复杂度,下面展示代码:

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	if (pq->phead == NULL && pq->plist == NULL)   
	{
		pq -> phead = pq -> plist = Queuebuynode(x);
	}
	else
	{
		list* newnode = Queuebuynode(x);
		pq->plist->next = newnode;
		pq->plist = newnode;
	}
	pq->size++;
}

 2.3.出队列

  我们既然讲了入队列,那么就会在讲述出队列,其实就是单链表的头删,因为前面说过队列是双向的,所以是从尾部进,头部出,此时我们需要先判断一下队头是否为空,如果为空的话那么出队列就没意义了,所以我们需要设置一个布朗类型的函数来检查一下队列是不是空的,下面小编直接给上代码:

bool panduan(Queue * ps)   //判断队列是不是空的
{
	assert(ps);
	return ps->phead == NULL && ps->plist == NULL;
}

  在判断完以后,我们就可以进行头删操作,此时我们同样也需要分为两种情况,一种情况就是队列中只有一个数据的情况,此时我们可以直接把头结点释放掉,然后把队头和队尾同时变成空就好了,另一种情况我们先保存队头下一个结点的数据,然后我们让队头直接free掉,然后我们让头结点的下一个结点变为头结点就好了,此时我们就实现了队列的出队列操作,下面是实现的代码图:

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	if (pq->phead == pq->plist)
	{
		free(pq->phead);
		pq->phead = pq->plist = NULL;
	}
	else
	{
		list* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

 2.4.获取队头元素

  这个操作其实是蛮简单的,因为队列就是保存着队头的,但是这里我们一定要小心踩坑,如果队伍为空的话,我们是无法获取队头元素的,所以我们需要先判定一下队列是否为空,不为空的话我们直接返回队头里面存的数据即可,下面直接给上代码图:

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	return pq->phead->data;
}

 2.5.获取队尾元素

  这个其实和获取队头数据是一样的,首先都需要判定队列是不是空的,如果不为空,我们直接返回队尾中存放的元素即可,下面给代码图:

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	return pq->plist->data;
}

 2.6.队列中有效元素的个数

  还记着小编在设置队列的时候多设置出的一个size吗?那个size的作用就是为了记录队列中有效的元素个数的,细心的读者朋友可能发现了小编在上面的入队操作时,最后写了个size++,小编那时候没说过它的作用(绝对不是忘了),就是为了这里说,我们每入队一个元素,就使队列中的元素加了一个,每次出队的时候,让size减少一个,代表着有效个数减少一个,所以此时我们想要获取队伍中有效元素的个数,直接返回size即可,下面是代码图:

int QueueSize(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	return pq->size;
}

 2.7.队列的销毁

  队列的销毁和栈比起来算是比较繁琐的,此时我们需要先判断一下队列是否为空,如果为空的话我们就不必销毁了,直接报警告就好,之后我们先把用一个指针保存着队头数据,以这个指针为循环条件,然后可以先保存好队头的下一个结点,之后将队头释放,让队头的下一个结点变成队头,之后经过层层循环以后,我们就可以把队列的元素层层释放,之后我们循环结束以后,再把队头给销毁,然后队列中有效的元素变成空即可,此时我们就完成了销毁功能,下面是代码:

void QueueDestroy(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	list* pour = pq->phead;
	while (pour)
	{
		list* next = pour->next;
		free(pour);
		pour = next;
	}
	pq->phead = pq->plist = NULL;
	pq->size = 0;
}

   此时我们已经将队列的一些功能给实现出来,但这些功能并不是全部,队列还能有许多功能,这里小编就先写小编学过的几种功能,至于其他功能就等着读者朋友们的探索了,那么可能很多读者朋友想要源码,小编这就把源码给发出来!

ac11b7d080df428db713506bf242d985.gif

3.代码展示 

  对了,队列小编也是分成了两个文件来书写,分别是用于声明函数的头文件,以及写函数1功能的源文件

 3.1.Queue.h

#include<stdlib.h>
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;

typedef struct list {
	QDataType data;
	struct list* next;
}list;

typedef struct Queue {
	struct list* phead;   //队头
	struct list* plist;   //队尾
	int size;
}Queue;

//队列的初始化
void QueueInit(Queue* pq);


//入队
void QueuePush(Queue* pq, QDataType x);



//出队
void QueuePop(Queue* pq);


//判断队列是不是空的
bool panduan(Queue* ps);



//取队头的元素
QDataType QueueFront(Queue* pq);


//取队尾的元素
QDataType QueueBack(Queue* pq);


//队列有效元素的个数
int QueueSize(Queue* pq);


//销毁队列
void QueueDestroy(Queue* pq);

 3.2.Queue.c

#include"Queue.h"
void QueueInit(Queue* pq)
{
	pq -> size = 0;
	pq->phead = NULL;
	pq->plist = NULL;
}



list* Queuebuynode(QDataType x)    //创建新结点的函数
{
	list* p1 = (list*)malloc(sizeof(list));
	assert(p1);
	p1->next = NULL;
	p1->data = x;
	return p1;  //别忘记返回,这个的类型是链表类型
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	if (pq->phead == NULL && pq->plist == NULL)   //很简单错误,c语言是没有连等这一回事的
	{
		pq -> phead = pq -> plist = Queuebuynode(x);
	}
	else
	{
		list* newnode = Queuebuynode(x);
		pq->plist->next = newnode;
		pq->plist = newnode;
	}
	pq->size++;
}



bool panduan(Queue * ps)   //判断队列是不是空的
{
	assert(ps);
	return ps->phead == NULL && ps->plist == NULL;
}


void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	if (pq->phead == pq->plist)
	{
		free(pq->phead);
		pq->phead = pq->plist = NULL;
	}
	else
	{
		list* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}


QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	return pq->phead->data;
}


QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	return pq->plist->data;
}


int QueueSize(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	return pq->size;
}



void QueueDestroy(Queue* pq)
{
	assert(pq);
	assert(!panduan(pq));
	list* pour = pq->phead;
	while (pour)
	{
		list* next = pour->next;
		free(pour);
		pour = next;
	}
	pq->phead = pq->plist = NULL;
	pq->size = 0;
}

总结

  以上就是队列的概念以及功能的实现,小编是栈和队列一起写的,写的有点快,所以可能有一些小编写的没有那么好,请各位见谅,如果文章有错误,恳请在评论区指出,小编一定及时的去更正,那么,我们下一篇文章见啦!

 c3b25ffe6c9f4730ad17161e36761821.jpeg

 

 

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

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

相关文章

基于Python的去哪儿网数据采集与分析可视化大屏设计与实现

摘要 本文旨在介绍如何利用Python进行去哪儿网景点数据的采集与分析。通过采集去哪儿网上的景点数据&#xff0c;我们可以获取大量的旅游相关信息&#xff0c;并基于这些数据进行深入分析和洞察&#xff0c;为旅游行业、市场营销策略以及用户个性化推荐等提供支持。 本文将使用…

MySQL(DQL)

一&#xff0c;SQL语言分类 &#xff08;1&#xff09;数据查询语言&#xff08;DQL&#xff1a;Data Query Language&#xff09;其语句&#xff0c;也称为 “数据检索语句”&#xff0c;用以从表中获得数据&#xff0c;确定数据怎样在应用程 序给出。关键字 SELECT 是 DQL&a…

Python打包命令汇总

1、pyinstaller打包 环境安装&#xff1a;pip install pyinstaller 网络不好可以通过 -i 指定安装源&#xff1a;pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple/安装完成后通过&#xff1a;pyinstaller --version 查看是否安装成功 打包单个脚本&…

操作系统笔记二

虚拟内存 把不常用的数据放到硬盘上去&#xff0c;常用的代码或者数据才加载到内存&#xff0c;来实现虚拟的大内存的感觉 覆盖技术 目标&#xff1a;在较小内存运行较大程序。 原理&#xff1a;把程序按自身逻辑结构划分若干功能上相对独立的程序模块。不回同时执行的模块共…

FreeRTOS学习笔记(一)—— 裸机和RTOS,Freertos移植(MDK),stm32cubeIDE使用Freertos

FreeRTOS学习笔记&#xff08;一&#xff09;—— 裸机和RTOS&#xff0c;Freertos移植&#xff08;MDK&#xff09;&#xff0c;stm32cubeIDE使用Freertos 文章目录 FreeRTOS学习笔记&#xff08;一&#xff09;—— 裸机和RTOS&#xff0c;Freertos移植&#xff08;MDK&#…

uniapp/vue个性化单选、复选组件

个性化单选和复选组件在网页设计中非常常见&#xff0c;它们不仅能够提升用户界面的美观度&#xff0c;还能改善用户体验。此组件是使用vue uniapp实现的个性化单选复选组件。设计完成后&#xff0c;点击生成源码即可。 拖动组件过设计区 每行显示数量 默认支持每行三个&#…

Maven-学习首篇

目录 Maven简介基本概念&特点Maven的安装与配置Maven基础概念及使用方法Maven的项目结构Maven的使用Maven的依赖管理Maven的生命周期和插件常见疑问Maven的插件机制是如何工作的&#xff1f;Maven的POM文件主要包含哪些内容&#xff1f;Maven的生命周期包括哪些阶段&#x…

【C++语言】list的构造函数与迭代器

1. list的介绍及使用 1.1 list的介绍 list的文档介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点…

C++中的IO流

目录 1.C语言的输入与输出 2.流是什么 3.CIO流 标准IO流 IO流的四个标志 C文件IO流 4.stringstream的简单介绍 1.C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键 盘)读取数据&#xff0c;并将值存放在变…

钢铁百科:A572Gr60和SA572Gr60材质分析、A572Gr60和SA572Gr60简介

A572Gr60和SA572Gr60是两种常用的结构钢板&#xff0c;它们在材质、执行标准、化学成分、力学性能、交货状态、应用范围和常用规格方面有所不同。 材质&#xff1a; A572Gr60&#xff1a;属于美国材料与试验协会&#xff08;ASTM&#xff09;标准下的A572系列高性能结构钢&…

UIAbility组件基础(一)

一、概述 UIAbility组件是一种包含UI的应用组件&#xff0c;主要用于和用户交互。UIAbility组件是系统调度的基本单元&#xff0c;为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。每一个UIAbility组件实例都会在最近任务列表中显示一个对应的任务。 U…

自研低代码海报制作平台学习分享计划

vue3组件库开发前面咱卷完了JuanTree组件&#xff0c;接下来一起来卷vue3低代码海报制作平台的基础组件实现。首先是拖拽基础组件的开发&#xff0c;整好把前面学习的知识点再运用进来。 文章目录 效果演示基本拖拽区域拖拽旋转其他效果待实现 录屏说明 看一步步实现的效果&…

C++--类和对象(二)

类和对象的基础定义可参看&#xff1a;C--类和对象&#xff08;一&#xff09;-CSDN博客 本篇讲述类和对象里相当重要的几个成员函数 目录 类的默认成员函数&#xff1a; 1.构造函数 2.析构函数 3.拷贝构造函数 &#xff08;1&#xff09;无限递归调用拷贝构造 &#xff…

在Ubuntu中重装Vscode(没有Edit Configurations(JSON)以及有错误但不标红波浪线怎么办?)

在学习时需要将vscode删除重装&#xff0c;市面上很多方法都不能删干净&#xff0c;删除之后拓展都还在。因此下面的方法可以彻底删除。注意&#xff0c;我安装时使用的是snap方法。 如果你的VScode没有Edit Configurations(JSON)&#xff0c;以及有错误但不标红波浪线的话&…

基于QT实现的TCP连接的网络通信(客户端)

上篇介绍了QT实现网络通信的服务器端&#xff0c;还没看服务器的朋友们先去上篇了解&#xff0c;这篇我来实现一下客户端的实现。 首先还是新建一个项目 选择mainwindow类 在通信前将.pro文件的第一行代码中追加network 窗口搭建 在mainwindow.ui中完成一下窗口的搭建 首先在…

序列建模之循环和递归网络 - 双向RNN篇

序言 在序列建模的广阔领域中&#xff0c;循环神经网络&#xff08; RNN \text{RNN} RNN&#xff09;以其独特的循环结构&#xff0c;在处理序列数据方面展现出了强大的能力。然而&#xff0c;传统的单向 RNN \text{RNN} RNN在处理某些复杂任务时&#xff0c;如自然语言处理中…

基于51单片机的士出租车计价器proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1-GOrUrYlyGZFfkiiO6i5yg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…

「Unity3D」TextMeshPro-Text(UI)无法拖放到TextMeshPro的属性面板上

继承MonoBehaviour&#xff0c;然后定义public TextMeshPro textPro&#xff0c;属性面板上就会有TextMeshPro的拖放槽&#xff08;slot&#xff09;&#xff0c;以配置含有TextMeshPro的组件对象&#xff08;GameObject&#xff09;。 但此时会发现&#xff0c;含有TextMeshPr…

李沐老师动手深度学习pytorch版本的读取fashion_mnist数据并用AlexNet模型训练,其中修改为利用本地的数据集训练

李沐老师的d2l.load_data_fashion_mnist里面没有root参数&#xff0c;所以只会下载&#xff0c;不能利用本地的fashion_mnist数据。所以我使用torchvision 的datasets里面FashionMNIST方法&#xff0c;又由于李沐老师此处是利用AlexNet模型来训练fashion_mnist数据&#xff0c;…

xiaomi pad 6PRO 小米平板6 pro hyperOS降级 澎湃os 降级MIUI 14 教程 免解锁BL 降级,168小时解锁绑定

小米平板 6 Pro 机型代号 &#xff1a;liuqin 降级MIUI 14 小米澎湃 OS 正式版 澎湃OS安卓发布日期卡刷包线刷包OS1.0.7.0.UMYCNXM14.02024-07-13miui_LIUQIN_OS1.0.7.0.UMYCNXM_d618a5c980_14.0.zipliuqin_images_OS1.0.7.0.UMYCNXM_20240705.0000.00_14.0_cn_8cbf5920be.…