[数据结构初阶]队列

news2025/1/11 2:30:12

鼠鼠我呀,今天写一个基于C语言关于队列的博客,如果有兴趣的读者老爷可以抽空看看,很希望的到各位老爷观点和点评捏!

在此今日,也祝各位小姐姐女生节快乐啊,愿笑容依旧灿烂如初阳,勇气与童真永不退色!

目录

1.队列的概念及结构

 2.对列的实现 

2.1.queue.h

2.2.queue.c

2.3.test.c

2.4.定义队列

2.5.初始化队列

2.6.队尾入队列

2.7.对头出队列

2.8.获取队列队头元素

2.9.获取队列队尾元素

2.10.获取队列中有效元素的个数

2.11.检测队列是否为空,如果为空返回非零结果,非空返回0

2.12.销毁队列 

 3.分析运行结果

4.ending


 

1.队列的概念及结构

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

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

对头:进行删除操作的一端称为队头 。

咱们画一个队列的想象图就很好理解上面几个概念:

其实很好理解,队列里面的数据元素就像排队一样,先进入队列的数据元素当然先出队列了。

 2.对列的实现 

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

而队列用链表实现的方案也是多种多样,只要满足队列的定义即可。鼠鼠我今天写一个方案(本方案基于无头单向非循环链表)各位佬们可以看看啊,俺先把三个文件和运行结果呈现如下:

2.1.queue.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>


typedef int QDatatype;

typedef struct QNode
{
	QDatatype _data;
	struct  QNode* _next;
}QNode;

typedef struct Queue
{
	int k;
	QNode* head;
	QNode* tail;
}Queue;

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

//队尾入数据
void QueuePush(Queue* q, QDatatype data);

//对头出数据
void QueuePop(Queue* q);

//获取队列对头元素
QDatatype QueueFront(Queue* q);

//获取队列队尾元素
QDatatype QueueBack(Queue* q);

//获取队列中有效元素个数
int QueueSize(Queue* q);

//检测队列是否为空,如果为空返回非零结果,非空返回0
bool QueueEmpty(Queue* q);

//销毁队列
void QueueDestory(Queue* q);

2.2.queue.c

#define _CRT_SECURE_NO_WARNINGS
#include"queue.h"

void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->k = 0;
}

void QueuePush(Queue* q, QDatatype data)
{
	assert(q);
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	tmp->_data = data;
	tmp->_next = NULL;
	if (q->tail == NULL)
	{
		q->head = q->tail = tmp;
	}
	else
	{
		q->tail->_next = tmp;
		q->tail = tmp;
	}
	q->k++;
}

void QueuePop(Queue* q)
{
	assert(q);
	assert(q->k > 0);
	QNode* next = q->head->_next;
	free(q->head);
	q->head = next;
	if (q->head == NULL)
	{
		q->tail = NULL;
	}
	q->k--;
}

QDatatype QueueFront(Queue* q)
{
	assert(q);
	assert(q->k > 0);
	return q->head->_data;
}

QDatatype QueueBack(Queue* q)
{
	assert(q);
	assert(q->k > 0);
	return q->tail->_data;
}

int QueueSize(Queue* q)
{
	assert(q);
	return q->k;
}

bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->tail == NULL;
}

void QueueDestory(Queue* q)
{
	assert(q);
	QNode* tmp = q->head;
	while (tmp)
	{
		QNode* next = tmp->_next;
		free(tmp);
		tmp = next;
	}
	q->k = 0;
	q->head = q->tail = NULL;
}

2.3.test.c

#define _CRT_SECURE_NO_WARNINGS
#include"queue.h"

int main()
{
	Queue q;
	QueueInit(&q);

	QueuePush(&q, 0);
	QueuePush(&q, 1);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	QueuePush(&q, 6);

	printf("%d\n", QueueSize(&q));

	printf("%d ", QueueFront(&q));

	printf("%d\n", QueueBack(&q));

	printf("%d ", QueueFront(&q));
	QueuePop(&q);

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

	QueueDestory(&q);

	return 0;
}

运行结果如图,至于为什么是这些个结果,我们详细看以下鼠鼠的队列方案是如何实现的。

2.4.定义队列

typedef int QDatatype;

typedef struct QNode
{
	QDatatype _data;
	struct  QNode* _next;
}QNode;

typedef struct Queue
{
	int k;
	QNode* head;
	QNode* tail;
}Queue;

老样子我们将int重命名成QDatatype,方便以后代码的维护。

让后定义并重命名结构体QNode充当队列节点 ,这些节点根据数据元素的入队列或者出队列按需申请或者释放。QNode中成员_data用来存放数据元素,QNode中成员_next用来链接下一个节点。

又由于基于无头单向非循环链表(以下简称链表)实现的队列在入队列和出队列时分别需要链表尾插和头删,而且经常需要知道队列中数据元素的个数,我们定义并重命名结构体Queue来维护上面需求:Queue中成员k用来记录队列中数据元素个数;成员head用来指向链表头节点;成员tail用来指向链表尾节点。

大概这样子:

2.5.初始化队列

void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->k = 0;
}

断言防止传入的结构体变量地址为空(因为这个地址不可能为空)。将head和tail置成NULL,将k置成0即可。 

2.6.队尾入队列

void QueuePush(Queue* q, QDatatype data)
{
	assert(q);
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	tmp->_data = data;
	tmp->_next = NULL;
	if (q->tail == NULL)
	{
		q->head = q->tail = tmp;
	}
	else
	{
		q->tail->_next = tmp;
		q->tail = tmp;
	}
	q->k++;
}

断言防止传入的结构体变量地址为空(这点以下不在赘述)。 队尾入队列其实就是链表尾插,先动态申请一个结构体QNode空间充当新节点,这个新节点的存放好想插入的数据元素,再让新节点链接好队列(链接队列是要区分队列是否为空),k加一即可。

2.7.对头出队列

void QueuePop(Queue* q)
{
	assert(q);
	assert(q->k > 0);
	QNode* next = q->head->_next;
	free(q->head);
	q->head = next;
	if (q->head == NULL)
	{
		q->tail = NULL;
	}
	q->k--;
}

断言防止队列为空仍然出队列。常规来说再进行链表头删、k减一即可完成出队列,但要注意如果队列中只有一个数据元素(或者说链表只有一个节点)时,如果按常规操作的话会使得tail变成野指针,用上面一个if语句很好处理问题。 

2.8.获取队列队头元素

QDatatype QueueFront(Queue* q)
{
	assert(q);
	assert(q->k > 0);
	return q->head->_data;
}

 断言防止队列为空仍然获取对头元素。返回head指向的节点成员_data即可。

2.9.获取队列队尾元素

QDatatype QueueBack(Queue* q)
{
	assert(q);
	assert(q->k > 0);
	return q->tail->_data;
}

  断言防止队列为空仍然获取对尾元素。返回tail指向的节点成员_data即可。

2.10.获取队列中有效元素的个数

int QueueSize(Queue* q)
{
	assert(q);
	return q->k;
}

根据设定可知,返回k即可。 

2.11.检测队列是否为空,如果为空返回非零结果,非空返回0

bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->tail == NULL;
}

若tail指向NULL说明队列为空(或者说链表为空),则q->tail==NULL为真,返回真。若队列不为空逻辑跟队列为空逻辑相反,返回假。 

2.12.销毁队列 

void QueueDestory(Queue* q)
{
	assert(q);
	QNode* tmp = q->head;
	while (tmp)
	{
		QNode* next = tmp->_next;
		free(tmp);
		tmp = next;
	}
	q->k = 0;
	q->head = q->tail = NULL;
}

遍历链表将节点(这些节点都是动态申请的)都释放掉,再将head和tail置成NULL,并将k置成0即可。

 3.分析运行结果

佬们请看:

第一条语句:定义一个结构体Queue变量q;

第二条语句:初始化结构体变量q;

第三条到第十条语句:数据元素0、1、1、2、3、4、5、6依次入队列,执行完后队列想象图为: 

第十一条语句:执行printf函数,打印队列有效元素个数为8并换行。

第十二条和第十三条语句:均执行printf函数,分别打印对头元素0和队尾元素6,换行。

第十四条语句: 执行printf函数,打印对头元素0。

第十五条语句:对头元素0出队列,执行完第十五条语句后队列想象图为:

接下来while循环:当队列不为空时,打印对头元素再对头元素出队列。所以分别打印1、1、2、3、4、5、6。执行完while循环后,队列为空(或者说链表为空)。

再接下来打印队列有效元素个数为0,印证队列为空。再销毁队列。

4.ending

感谢阅读,有不对的地方欢迎像本鼠拿捏玩偶一样拿捏鼠鼠捏!

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

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

相关文章

2024/3/7—2575. 找出字符串的可整除数组

代码实现&#xff1a; int* divisibilityArray(char *word, int m, int *returnSize) {int n strlen(word);int *res (int*)malloc(sizeof(int) * n);long cur 0;for (int i 0; i < n; i) {cur (cur * 10 (word[i] - 0)) % m;res[i] (cur 0) ? 1 : 0;}*returnSize …

[Unity实战]使用NavMeshAgent做玩家移动

其实除了Character Controller, Rigidbody&#xff0c;我们还可以使用NavMeshAgent去做。这么做的好处是能避免玩家去莫名其妙的地方&#xff08;毕竟基于烘焙过的导航网格&#xff09;&#xff0c;一般常见于元宇宙应用和mmo。 根据Unity手册&#xff0c;NavMeshAgent 也有和…

考研新手小白,必须提前了解的考研常识

关于考研需要知道的一些常识&#xff1a; 在大三上学期开学&#xff0c;通常是在9月左右&#xff0c;开始考虑选择学校和专业&#xff0c;购买相关资料&#xff0c;收集相关信息&#xff0c;启动研究生考试的复习计划。 接下来的年度&#xff08;即第四学年制的大四学期&…

C语言数据类型详解及相关题——各种奇奇怪怪的偏难怪

文章目录 一、C语言基本数据类型溢出 二、存储原理符号位原码反码补码补码操作的例子 三、赋值中的类型转换常见返回类型——巨坑总结 一、C语言基本数据类型 溢出 因为数据范围&#xff08;即存储单元的位的数量&#xff09;的限制&#xff0c;可以表达的位数是有限的。 溢出…

AtCoder Beginner Contest 343(A,B,C,D,E,F)

比赛链接 CE是暴力&#xff0c;D是数据结构题&#xff0c;F是线段树。这场的E比较有意思&#xff0c;其他的感觉有点水。 A - Wrong Answer 题意&#xff1a; 给你两个数 A , B A,B A,B ( 0 ≤ A , B ≤ 9 ) (0\le A,B\le 9) (0≤A,B≤9)&#xff0c;返回一个个位数&#…

手机app制作商用系统软件开发

手机端的用户占比已经超过了电脑端的用户量&#xff0c;企业想要发展手机端的业务就必须拥有自己的app软件&#xff0c;我们公司就是专门为企业开发手机软件的公司&#xff0c;依据我们多年的开发经验为大家提供在开发app软件的时候怎么选择开发软件的公司。 手机app制…

spring-jpa

一、介绍 1.1ORM 1.2 Java Persistence API 放在javaee版本 优点 支持持久化复杂的Java对象&#xff0c;简化Java应用的对象持久化开发支持使用JPQL语言进行复杂的数据查询使用简单&#xff0c;支持使用注解定义对象关系表之间的映射规范标准化&#xff0c;由Java官 方统一规…

阿里云服务器购买搭建

1.首先在阿里云官网购买ESC云服务器 2.在域名处&#xff0c;购买域名&#xff0c;申请免费的SSL证书&#xff0c;但是这个证书需要去备案&#xff0c;这个周期比较长。 3.登录你的服务器就可以安装你需要的环境&#xff0c;进行开发&#xff0c;当然使用docker很好用。 以下…

【开源物联网平台】FastBee认证方式和MQTT主题设计

&#x1f308; 个人主页&#xff1a;帐篷Li &#x1f525; 系列专栏&#xff1a;FastBee物联网开源项目 &#x1f4aa;&#x1f3fb; 专注于简单&#xff0c;易用&#xff0c;可拓展&#xff0c;低成本商业化的AIOT物联网解决方案 目录 一、接入步骤 1.1 设备认证 1.2 设备交…

【Leetcode】3028.边界上的蚂蚁

题目描述 思路 题目中要求我们返回 蚂蚁返回到边界的次数。简单来想&#xff0c;就是蚂蚁原来的位置的一维坐标为0&#xff0c;然后经过&#xff0c;若干次移动&#xff0c;统计有几次坐标再次变为0的个数。 我们利用前缀和&#xff0c;像定义一个数组&#xff0c;算出前缀和数…

贪心算法详解及机器人运动应用Demo

一、引言 贪心算法是一种在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是全局最好或最优的算法。贪心算法在有最优子结构的问题中尤为有效。今天&#xff0c;我们将通过一个机器人运动的Demo来详细解析贪心算…

网络编程作业day7

作业项目&#xff1a;基于UDP的聊天室 服务器代码&#xff1a; #include <myhead.h>//定义客户信息结构体 typedef struct magtye {char type; //消息类型char name[100]; //客户姓名char text[1024]; //客户发送聊天信息 }msg_t;//定义结构体存储…

基于YOLOv5的驾驶员疲劳驾驶行为​​​​​​​检测系统

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文主要内容:详细介绍了疲劳驾驶行为检测整个过程&#xff0c;从数据集到训练模型到结果可视化分析。 博主简介 AI小怪兽&#xff0c;YOLO骨灰级玩家&#xff0c;1&#xff09;YOLOv5、v7、v8优化创新&#xff0c;轻松涨点和模型轻量…

Java特性之设计模式【过滤器模式】

一、过滤器模式 概述 ​ 过滤器模式&#xff08;Filter Pattern&#xff09;或标准模式&#xff08;Criteria Pattern&#xff09;是一种设计模式&#xff0c;这种模式允许开发人员使用不同的标准来过滤一组对象&#xff0c;通过逻辑运算以解耦的方式把它们连接起来。这种类型的…

几何工具的使用

Geometry - Creation 创建几何 CogCreateCircleTool&#xff1a;创建圆CogCreateEllipseTool:创建椭圆CogCreateLineBisectPointsTool&#xff1a;带有两个点的平行线CogCreateLineParallelTool:在某一点创建某条线的平行线CogCreateLinePerpendicularTool:在某一点创建某条线…

STL中push_back和emplace_back效率的对比

文章目录 过程对比1.通过构造参数向vector中插入对象&#xff08;emplace_back更高效&#xff09;2.通过插入实例对象&#xff08;调用copy函数&#xff09;3.通过插入临时对象&#xff08;调用move函数&#xff09; 效率对比emplace_back 的缺点 我们以STL中的vector容器为例。…

力扣每日一题 找出字符串的可整除数组 数论

Problem: 2575. 找出字符串的可整除数组 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 灵神题解 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public int[] divisibilityArray(String word, int m){in…

外包干了一周,技术明显倒退。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

【JavaEE初阶】 JVM 运行时数据区简介

文章目录 &#x1f343;前言&#x1f332;堆&#xff08;线程共享&#xff09;&#x1f384;Java虚拟机栈&#xff08;线程私有&#xff09;&#x1f38b;本地方法栈&#xff08;线程私有&#xff09;&#x1f333;程序计数器&#xff08;线程私有&#xff09;&#x1f334;方法…

ospf虚链路实验简述

1、ospf虚链路实验简述 ospf虚链路配置 为解决普通区域不在骨干区域旁&#xff0c;通过配置Vlink-peer实现不同区域网络设备之间建立逻辑上的连接。 实验拓扑图 r1: sys sysname r1 undo info enable int loopb 0 ip add 1.1.1.1 32 ip add 200.200.200.200 32 quit int e0/0/…