队的简单介绍

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

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

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

入队列如下图所示:

出队列如下图所示:

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,需要挪动后面的队员,效率会比较低。使用单链表的话只需要执行头删的操作即可。

队列的头文件:Queue.h文件:

队员和队头尾指针的关系:

cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


// 创建队的节点(队员)
typedef int QDataType;   // 需要存放其他数据将int改为对应数据类型即可
typedef struct QueueNode
{
	struct QueueNode* _next;
	QDataType _data;
}QueueNode;

// 创建队(队头指针,队尾指针)
typedef struct Queue
{
	QueueNode* _phead;
	QueueNode* _ptail;
}Queue;

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

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

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

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

// 获取队列头部元素 
QDataType QueueFront(Queue* pq);

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

// 队员个数
int QueueSize(Queue* pq);

// 检测队列是否为空,如果为空返1,如果非空返回0 
int QueueEmpty(Queue* pq);

队列的实现:Queue.c文件:

队列的初始化和销毁:

初始化只需要将头尾指针置空即可;销毁创建一个指针=头指针和一个指针保存头指针指向的下一个队员的地址。逐一释放之后头尾指针都要置空避免成为野指针造成非法访问。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include "Queue.h"

// 队的初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->_phead = pq->_ptail = NULL;
}

// 队的销毁
void QueueDestroy(Queue* pq)
{
	Queue* pcur = pq->_phead;
	while (pcur)
	{
		Queue* next = pcur->_phead->_next;
		free(pcur);
		pcur = next;
	}
	pq->_phead = pq->_ptail = NULL;
}

入队列和出队列:

入队列相当于是单链表的尾插,这里使用的是malloc()函数,参数为申请开辟的字节个数,返回开辟后的空间地址。同样判断是否开辟成功,若失败则打印原因,成功则_data赋值x,_next指针置空。入队如果对空则队头队尾指针都指向newnode,否则队尾的_next指针指向newnode,队尾指针向后移动到newnode的位置。

出队相当于头删,需要断言队不为空队。创建一个队员指针指向队头的下一个队员,然后删掉队头,让队头指针指向下一个成员,即刚刚保存的指针。如果队员全部出队之后队头指针为空,再将队尾指针置空避免成为野指针。

cpp 复制代码
// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));

	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->_data = x;
	newnode->_next = NULL;
	// 入队
	if (pq->_phead == NULL)
	{
		pq->_phead = pq->_ptail = newnode;
	}
	else
	{
		pq->_ptail->_next = newnode;
		pq->_ptail = newnode;
	}
}

// 队头出队列 
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->_phead);

	QueueNode* nodenext = pq->_phead->_next;
	free(pq->_phead);
	pq->_phead = nodenext;

	// 删完了队头尾指针都要置空
	if (pq->_phead == NULL)
	{
		pq->_phead = pq->_ptail = NULL;
	}
}

取队头和队尾的元素都是直接返回队头队尾指针指向的_data数据即可。

队员的个数,需要遍历整个队伍,采用计数器的方法,记录再将其返回即可。

判断队伍是否空队伍和栈一样使用三目操作符完成。

cpp 复制代码
// 获取队列头部元素 
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->_phead);

	return pq->_phead->_data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->_phead);

	return pq->_ptail->_data;
}

// 队员个数
int QueueSize(Queue* pq)
{
	assert(pq);
	assert(pq->_phead);

	int size = 0;
	QueueNode* pcur = pq->_phead;
	while (pcur)
	{
		size++;
		pcur = pcur->_next;
	}
	return size;
}

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

	return pq->_phead == NULL ? 1 : 0;
}

队的实现测试test.c文件:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include "Queue.h"

void test()
{
	Queue q;

	QueueInit(&q);

	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

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

	while (!QueueEmpty(&q))             // 利用队伍不为空队作为循环条件
	{
		printf("%d ", QueueFront(&q));  // 取队头元素
		QueuePop(&q);                   // 取队头元素之后要执行出队操作
	}
	printf("\n");

	QueueDestroy(&q);
}

int main()
{
	test();

	return 0;
}

结论:本文介绍了队列数据结构的基本概念和链式实现方法。队列是一种先进先出(FIFO)的线性表,支持在队尾插入(入队)和队头删除(出队)操作。文章详细阐述了用单链表实现队列的优势,相比数组实现避免了数据搬移的开销。代码实现包含队列初始化、销毁、入队、出队等核心操作,以及获取队头队尾元素、队列大小和判空等辅助功能。测试用例展示了队列的基本使用方法。整个实现通过头指针和尾指针管理队列,出队时执行头删操作,入队时执行尾插操作,确保了操作的高效性。

相关推荐
2601_949146535 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
知南x7 小时前
【Ascend C系列课程(高级)】(1) 算子调试+调优
c语言·开发语言
2的n次方_8 小时前
Runtime 执行提交机制:NPU 硬件队列的管理与任务原子化下发
c语言·开发语言
凡人叶枫9 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
凡人叶枫11 小时前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
傻乐u兔12 小时前
C语言进阶————指针3
c语言·开发语言
CodeSheep程序羊13 小时前
拼多多春节加班工资曝光,没几个敢给这个数的。
java·c语言·开发语言·c++·python·程序人生·职场和发展
I'mChloe13 小时前
PTO-ISA 深度解析:PyPTO 范式生成的底层指令集与 NPU 算子执行的硬件映射
c语言·开发语言
2的n次方_13 小时前
Runtime 内存管理深化:推理批处理下的内存复用与生命周期精细控制
c语言·网络·架构
嵌入小生00714 小时前
标准IO---核心函数接口延续(嵌入式Linux)
c语言·vscode·vim·嵌入式·小白·标准io·函数接口