【数据结构初阶】六、线性表中的队列(C语言 -- 链式结构实现队列)

news2024/12/23 17:26:37

=========================================================================

相关代码gitee自取

C语言学习日记: 加油努力 (gitee.com)

 =========================================================================

接上期

【数据结构初阶】五、线性表中的栈(C语言 -- 顺序表实现栈)_高高的胖子的博客-CSDN博客

 =========================================================================

                     

1 . 队列(Queue)

队列的概念和结构:

队列的概念

  • 队列是一种只允许在一端执行插入数据操作另一端进行删除数据操作特殊线性表
                      
  • 入队列 -- 进行插入操作的一端称为队尾
    出队列 -- 进行删除操作的一端称为队头

                
  • 队列中的数据元素遵守
    先进先出FIFO -- First In First Out)的原则 -- 先进入的元素会先出来
    所以可以应用在公平性排队(抽号机)、BFS(广度优先遍历)
                        

队列的结构

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

2 . 队列的实现

                

使用 顺序表(数组)链表(链式结构) 都可以实现队列

使用顺序表的话,入队列比较简单,但在出队列时需要删除和挪动数据效率较低

所以下面用链表(链式结构)实现队列  --  单向 + 无头 + 非循环 链表

入队 -- 单链表尾部插入(尾插)         ;      出队 -- 单链表头部删除(头删)

               

(详细解释在图片的注释中,代码分文件放下一标题处)

               

实现具体功能前的准备工作

  • 定义队列(链式结构)中数据域存储的数据类型
                               
  • 定义队列(链式结构)结点类型
    包含 队列指针域 队列数据域
                 
  • 定义队列类型
    包含 头结点指针尾结点指针 和 队列结点(元素)个数
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueInit函数 -- 将队列进行初始化

  • assert断言队列类型指针不为空
                               
  • 队头结点置为空
    队尾结点置为空
    队列结点(元素)个数置为0
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueDestroy函数 -- 将队列销毁

  • assert断言队列类型指针不为空
                               
  • 创建一个在队列进行遍历的指针cur
    使用while循环进行遍历释放队列结点
                 
  • 结点都释放后,把队头队尾指针都置空
                   
  • 再把队列结点(元素)个数置为0
图示

            

            

---------------------------------------------------------------------------------------------

            

QueuePush函数 -- 用链表的尾插操作实现入队

  • assert断言队列类型指针不为空
                               
  • 为队列结点开辟动态空间检查空间开辟情况
                 
  • 结点开辟成功
    尾插值(x)赋给队列结点的数据域并将指针域置为空
                   
  • 空间开辟后进行尾插
    如果队列刚初始化队列为空,将刚开辟的结点newnode地址赋给头尾结点指针
    队列不为空正常进行尾插操作
                
  • 插入数据后队列结点(元素)个数++
图示

            

            

---------------------------------------------------------------------------------------------

            

QueuePop函数 -- 用链表的头删操作实现出队

  • assert断言队列类型指针不为空队列不为空
                               
  • 出队(头删)分两种情况
    队列中只剩一个结点 -- 头删后头指针移动尾指针也要移动
    队列不止一个结点 -- 头删后只需移动队头结点
                 
  • 删除队列结点(元素)个数--
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueFront函数 -- 返回队头结点的数据域数据

  • assert断言队列类型指针不为空队列不为空
                               
  • 队列有数据,则直接返回队头结点数据域数据
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueBack函数 -- 返回队尾结点的数据域数据

  • assert断言队列类型指针不为空队列不为空
                               
  • 队列有数据,则直接返回队尾结点数据域数据
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueEmpty函数 -- 判断队列是否为空

  • assert断言队列类型指针不为空
                               
  • 直接判断队头结点指向的下个结点是否为空直接返回判断结果
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueSize函数 -- 判断队列结点(元素)个数

  • assert断言队列类型指针不为空
                               
  • 直接返回size队列结点(元素)个数
图示

            

            

---------------------------------------------------------------------------------------------

            

总体测试:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

3 . 对应代码

Queue.h -- 队列头文件

#pragma once

//包含之后需要的头文件:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

//以链表(链式结构)实现队列:
//双向+循环 的链表可以解决找尾结点的问题,
//定义一个尾指针也可以解决该问题,
//哨兵位 可以解决二级指针的问题,
//且尾插时可以少一层判断,但还有方法可以解决


//定义队列(链式结构)中数据域存储的数据类型:
typedef int QDataType;

//定义队列(链式结构)结点类型:
typedef struct QueueNode
{
	//队列指针域:
	struct QueueNode* next;

	//队列数据域:
	QDataType data;

}QNode; //将类型重命名为Qnode


//定义队列类型:
typedef struct Queue
{
	//因为用链表尾插实现入队,
	//用链表头删实现出队,
	//那么就需要头结点和尾结点的指针,
	//所以可以直接将这两个指针封装为一个类型,
	//队列类型:

	//头结点指针:
	QNode* head;

	//尾结点指针:
	QNode* tail;

	//记录队列结点(元素)个数:
	int size; 

	//这样之后在出队和入队操作时,
	//就不需要用到二级指针,
	//直接接收这个结构体指针,
	//通过结构体指针运用结构体里的头尾结点指针,
	//再用头尾结点指针定义头尾结点
	//来实现 二级指针、带哨兵位头结点 和 返回值 的作用
	//所以现在已知的通过指针定义结点的方法就有4种:
	//		1. 结构体包含结点指针
	//		2. 二级指针调用结点指针
	//		3. 哨兵位头结点指针域next指向结点地址
	//		4. 返回值返回改变的结点指针

}Que; //重命名为Que


//队列初始化函数 -- 将队列进行初始化
//接收队列类型指针(包含链表头尾结点) 
void QueueInit(Que* pq);

//队列销毁函数 -- 将队列销毁
//接收队列类型指针(包含链表头尾结点) 
void QueueDestroy(Que* pq);

//队列入队函数 -- 用链表的尾插操作实现入队
//接收队列类型指针(包含链表头尾结点) 、尾插值
void QueuePush(Que* pq, QDataType x);

//队列出队函数 -- 用链表的头删操作实现出队
//接收队列类型指针(包含链表头尾结点) 
void QueuePop(Que* pq);

//队头函数 -- 返回队头结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueFront(Que* pq);

//队尾函数 -- 返回队尾结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueBack(Que* pq);

//判空函数 -- 判断队列是否为空
//接收队列类型指针(包含链表头尾结点) 
bool QueueEmpty(Que* pq);

//队列大小函数 -- 判断队列结点(元素)个数
//接收队列类型指针(包含链表头尾结点) 
int QueueSize(Que* pq);

            

            

---------------------------------------------------------------------------------------------

                

Queue.c -- 队列函数实现文件

#define _CRT_SECURE_NO_WARNINGS 1

//包含队列头文件:
#include "Queue.h"

//队列初始化函数 -- 将队列进行初始化
//接收队列类型指针(包含链表头尾结点) 
void QueueInit(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);

	//将队头结点置为空:
	pq->head = NULL;

	//将队尾结点置为空:
	pq->tail = NULL;

	//队列结点(元素)个数置为0:
	pq->size = 0;
}



//队列销毁函数 -- 将队列销毁
//接收队列类型指针(包含链表头尾结点) 
void QueueDestroy(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);

	//释放队列跟单链表的释放一样
	//先创建一个在队列进行遍历的指针:
	QNode* cur = pq->head; //从队头结点开始

	//使用while循环进行遍历释放队列结点:
	while (cur != NULL)	
	{
		//先保存下个结点:
		QNode* next = cur->next;

		//再释放当前结点:
		free(cur);

		//再指向下个结点:
		cur = next;
	}

	//结点都释放后,把队头队尾指针都置空:
	pq->head = NULL;
	pq->tail = NULL;

	//再把队列结点(元素)个数置为0:
	pq->size = 0;
}



//队列入队函数 -- 用链表的尾插操作实现入队
//接收队列类型指针(包含链表头尾结点) 、尾插值
void QueuePush(Que* pq, QDataType x)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);

	//入队放入元素需要空间,
	//所以要先为队列结点开辟动态空间:
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	//检查是否开辟成功:
	if (newnode == NULL)
	{
		//开辟失败则打印错误信息:
		perror("malloc fail");
		//终止程序:
		exit(-1);
	}

	//队列结点完成后将尾插值(x)
	//赋给队列结点数据域:
	newnode->data = x;
	//指针域指向空:
	newnode->next = NULL;

	//空间开辟后进行尾插:
	if (pq->tail == NULL)
		//如果队列刚初始化,队列为空,
		//头结点指针和尾结点指针都为空:
	{
		//那么将刚开辟的结点newnode地址
		//赋给头结点指针和尾结点指针
		pq->head = newnode;
		pq->tail = newnode;
	}
	else
		//队列不为空,进行尾插:
	{
		//将目前队尾结点指针域next指向尾插结点:
		pq->tail->next = newnode;
		//然后再指向尾插结点,成为新队尾结点:
		pq->tail = newnode;
	}

	//插入数据后队列结点(元素)个数++:
	pq->size++;
}



//队列出队函数 -- 用链表的头删操作实现出队
//接收队列类型指针(包含链表头尾结点) 
void QueuePop(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);
	//assert断言队列不为空,没数据不能删除:  
	assert(QueueEmpty != true); //不为空就继续程序

	//如果队列中只剩一个结点:
	if (pq->head->next == NULL)
		//队头指针指向空,说明只剩一个结点,
		//只剩一个结点说明队头队尾指针都指向这一个结点,
		//所以这时头删后头指针移动,尾指针也要移动
	{
		//先释放("删除")队列目前头结点:
		free(pq->head);

		//删除后将队头队尾指针都置为空:
		pq->head = NULL;
		pq->tail = NULL;
	}
	else
		//队列不止一个结点,则头删后只需移动队头结点:
	{
		//用链表的头删操作实现出队,
		//先保存第二个结点地址:
		QNode* next = pq->head->next;

		//释放("删除")队列目前头结点:
		free(pq->head);

		//再将队头结点指针指向原本第二个结点next,
		//让其成为新的队头结点:
		pq->head = next;
	}

	//“删除”后队列结点(元素)个数--:
	pq->size--; 
}



//队头函数 -- 返回队头结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueFront(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);
	//assert断言队列不为空,没数据不能查找:  
	assert(QueueEmpty != true); //不为空就继续程序

	//队列有数据,则直接返回队头结点数据域数据:
	return pq->head->data;
}



//队尾函数 -- 返回队尾结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueBack(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);
	//assert断言队列不为空,没数据不能查找:  
	assert(QueueEmpty != true); //不为空就继续程序

	//队列有数据,则直接返回队尾结点数据域数据:
	return pq->tail->data;
}



//判空函数 -- 判断队列是否为空
//接收队列类型指针(包含链表头尾结点) 
bool QueueEmpty(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);

	//直接判断队头结点指向的下个结点是否为空:
	return pq->head == NULL; 
	//是则返回true -- 队列为空
	//是则返回false -- 队列不为空
}


//队列大小函数 -- 判断队列结点(元素)个数
//接收队列类型指针(包含链表头尾结点) 
int QueueSize(Que* pq)
{
	//assert断言队列类型指针不为空:
	assert(pq != NULL);

	//直接返回size队列结点(元素)个数:
	return pq->size;
}

            

            

---------------------------------------------------------------------------------------------

                

Test.c -- 队列测试文件

#define _CRT_SECURE_NO_WARNINGS 1

//包含队列头文件:
#include "Queue.h"

//队列测试函数:
void TestQueue()
{
	//创建队列类型:
	Que q;

	//对队列类型进行初始化:
	QueueInit(&q);

	//进行入队操作:
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);

	//当前队尾值:
	printf("当前队尾值:%d\n", QueueBack(&q));

	//当前队列元素个数:
	printf("当前队列元素个数:%d\n", QueueSize(&q));

	//换行:
	printf("\n");

	//使用while循环遍历进行出队:
	//(类似抽号机,当前号抽完就到下个号)
	while (!QueueEmpty(&q))
		//队列不为空就继续出队:
	{
		//打印出队值:
		printf("当前出队值为:%d\n", QueueFront(&q));
		//进行出队:
		QueuePop(&q); //出队后打印下个出队值
	}

	//换行:
	printf("\n");

	//当前队列元素个数:
	printf("当前队列元素个数:%d", QueueSize(&q));

	//销毁队列:
	QueueDestroy(&q);
}

//主函数:
int main()
{
	//调用队列测试函数:
	TestQueue();

	return 0;
}

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

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

相关文章

如何利用niceGUI构建一个流式单轮对话界面

官方文档 参考文档 import asyncio import time import requests from fastapi import FastAPI from nicegui import app, uiclass ChatPage:temperature: ui.slider Nonetop_p: ui.slider Noneapi_key: ui.input Nonemodel_name: ui.input Noneprompt: ui.textarea None…

番外5:下载+安装+配置Linux

任务前期工作&#xff1a; 01. 电脑已安装好VMware Workstation软件&#xff1b; 02.提前下载好Rhel-8.iso映像文件&#xff08;文件较大一般在9.4GB&#xff0c;建议采用迅雷下载&#xff09;&#xff0c;本人使用的以下版本&#xff08;地址ed2k://|file|rhel-8.4-x86_64-dvd…

Tomcat启动后的日志输出为乱码

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

实现三栏布局的十种方式

本文节选自我的博客&#xff1a;实现三栏布局的十种方式 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是MilesChen&#xff0c;偏前端的全栈开发者。&#x1f4dd; CSDN主页&#xff1a;爱吃糖的猫&#x1f525;&#x1f4e3; 我的博客&#xff1a;爱吃糖的猫&…

Mysql技术文档--之Mysql联查使用-快速了解联查看我这一篇就够了!国庆开卷!

阿丹&#xff1a; 开头先祝贺大家国庆快乐&#xff01;&#xff01;&#xff01; 在MySQL中&#xff0c;联结&#xff08;JOIN&#xff09;是用于将两个或多个表中的数据根据指定的条件进行关联查询的操作。通过联结&#xff0c;你可以从多个表中检索相关的数据&#xff0c;并…

市场调研的步骤与技巧:助你了解市场需求

在当今快速发展的市场中&#xff0c;进行有效的市场研究对于了解消费者的行为、偏好和趋势至关重要。适当的市场研究可以帮助公司获得对目标受众的有价值的见解&#xff0c;创造更好的产品和服务&#xff0c;并提高客户满意度。今天&#xff0c;小编和大家一起讨论一下怎么做市…

10.1 今日任务:select实现服务器并发

#include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__); \perror(msg);\ }while(0)#define PORT 8888 //端口号&#xff0c;范围1024~49151 #define IP "192.168.112.115" //本机IP&#xff0c;ifco…

[Linux] 4.常用初级指令

pwd&#xff1a;显示当前文件路径 ls:列出当前文件夹下有哪些文件 mkdir空格文件名&#xff1a;创建一个新的文件夹 cd空格文件夹名&#xff1a;进入文件夹 cd..&#xff1a;退到上一层文件夹 ls -a&#xff1a;把所有文件夹列出来 .代表当前文件夹 ..代表上层文件夹 用…

第 365 场 LeetCode 周赛题解

A 有序三元组中的最大值 I 参考 B B B 题做法… class Solution { public:using ll long long;long long maximumTripletValue(vector<int> &nums) {int n nums.size();vector<int> suf(n);partial_sum(nums.rbegin(), nums.rend(), suf.rbegin(), [](int x…

Facebook Delos 中的虚拟共识协议

背景 Facebook 的软件系统栈一般包括两层&#xff1a;上层是数据平面&#xff0c; 下层是控制平面。 facebook software stack 数据平面包括大量的服务&#xff0c;他们需要存储和处理海量数据。控制平面用来支撑数据平面&#xff0c;起到一些控制作用&#xff1a;调度、配置…

XSS-labs

XSS常见的触发标签_xss标签_H3rmesk1t的博客-CSDN博客 该补习补习xss漏洞了 漏洞原理 网站存在 静态 和 动态 网站 xss 针对的网站 就是 动态网站 动态网站会根据 用户的环境 与 需求 反馈出 不同的响应静态页面 代码写死了 只会存在代码中有的内容 通过动态网站 用户体…

2023年中国火化设备行业现状分析:随着城市化进程的推进,市场需求将持续增长[图]

火化设备行业是指生产和提供用于尸体火化处理的设备和相关服务的行业。火化设备主要用于将尸体进行高温焚烧&#xff0c;将尸体转化为骨灰&#xff0c;以达到尸体处理和殡葬的目的。 火化设备行业优点 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 我国火…

C++面试八股(一)

目录 C和C的区别 1、语言特性 2、内存管理 3、C的库更加丰富 4、对异常的处理 什么是封装继承多态&#xff1f; 封装 继承 多态 new和malloc的区别 STL容器有哪些&#xff1f;容器对应的使用场景&#xff1f;&#xff08;挑一个你认为最熟悉的容器&#xff09; vector、…

评估指标Pre\Rec\F1\AUC

AUC的计算方法同时考虑了分类器对于正例和负例的分类能力&#xff0c;在样本不平衡的情况下&#xff0c;依然能够对分类器作出合理的评价。AUC代表模型预估样本之间的排序关系&#xff0c;即正负样本之间预测的gap越大&#xff0c;auc越大. 来自 https://blog.csdn.net/pearl8…

wustctf2020_name_your_cat

wustctf2020_name_your_cat Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)32位&#xff0c;开了NX和canary int shell() {return system("/bin/sh"); }有个后门函数 unsigned int…

AutoHotkey ---- 统一所有软件的快捷键(分析篇)

文章目录 引言理论编程方案 引言 快捷键大家都不陌生.但是目前的快捷键普遍存在以下几个问题。 不统一,即word、ppt、浏览器、各种编辑器、邮件客户端等等&#xff0c;都有属于自己的一套快捷键。快捷键冲突&#xff0c;即不同软件使用了相同的快捷键&#xff0c;而且作用域是…

GNN PyG~torch_geometric 学习理解

目录 1. PyG Introduction 2. PyG Installation 2.1 PyG 安装常见错误及原因 2.2 PyG 具体安装步骤 3. torch_geometric packages torch_geometric.data.Data Dataset 与 DataLoader Dropout、BatchNorm 3. torch_geometric: 理解edge_index 3.1 理解 mini-batch edg…

[H5动画制作系列]帧代码运行顺序测试

刚开始接触Animate CC(过去叫:Flash),对于帧代码的执行顺序十分迷惑。所以,专门做一个简单代码顺序测试. 准备工作: 代码图层actions,第1帧和第10帧为关键帧。 背景图层bg,就一个字符串红色Test.界面如下: 代码测试步骤: 第1帧参考代码如下: 第10帧参考代码如下: …

​68条萝卜刀《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

​68条萝卜刀《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书 ​68条萝卜刀《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

打包python模块代码到pypi

python中&#xff0c;我们会在自己业务中&#xff0c;重复性的使用某些功能。我们可以把这些公用的模块&#xff0c;打包上传&#xff0c;然后给需要的人使用&#xff0c;pypi给我们提供了这个机会 本期目录 一、准备工作 二、编写文件 三、上传下载 一、准备工作 1、需要git…