队列是先进先出结构,与栈的先进后出相反,但思路一样不是很难。
队列的应用:
- 任务调度: 操作系统中使用队列来进行任务调度,如进程调度、I/O请求等。
- 消息传递: 在网络通信中使用队列来传递消息。
- 广度优先搜索(BFS): 在图的遍历中使用队列来实现广度优先搜索算法。
- 缓存管理: 缓存中的数据通常按照队列的原则进行管理,最早进入缓存的数据最先被淘汰。
一、原理
队列的插入删除就如上图所示,结构的选择可以是链表有也可以是数组--顺序表。但是顺序表每删除一个数据就要对其余数据进行挪动,时间复杂度更大,所以我选择用链表讲解。
二、实现
我们使用不带头不循环单链表。
typedef int QListDataNode;
typedef struct QListNode
{
QListDataNode data;//数据
struct QListNode* next;//指向下一个节点的指针
}QListNode;
typedef struct QList
{
QListNode* phead;//头指针
QListNode* ptail;//尾指针
int size;//大小
}QList;
我在这里又创建了一个结构体,来包括头指针,和尾指针,方便插入删除。
队列的访问,只访问头元素和末尾元素。所以加了size这个成员,可以让我们在写返回数据个数的时候直接返回size而不需要遍历链表,更加高效,如果对队列有什么需求都可以直接加在这个结构体里面,很方便。
链表的队列插入是尾插,删除是头删。可以避免头插、尾删时的遍历链表找尾节点的前一个节点,从而节约时间。
队列的代码除了插入和删除,也是十分简单。
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int QListDataNode;
typedef struct QListNode
{
QListDataNode data;
struct QListNode* next;
}QListNode;
typedef struct QList
{
QListNode* phead;
QListNode* ptail;
int size;
}QList;
//初始化队列
void QInit(QList* Q);
//销毁队列
void QDestory(QList* Q);
//尾插入队列
void QPush(QList* Q, QListDataNode x);
//头删出队列
void QPop(QList* Q);
//返回队列头元素
QListDataNode QFront(QList* Q);
//返回队列尾元素
QListDataNode QBack(QList* Q);
//返回队列大小
int QSize(QList* Q);
//判断队列是非为空
int QEmpety(QList* Q);
void QInit(QList* Q)
{
assert(Q);
Q->size = 0;
Q->phead = Q->ptail = NULL;
}
void QDestory(QList* Q)
{
assert(Q);
while (!QEmpety(Q))
{
QPop(Q);
}
}
void QPush(QList* Q, QListDataNode x)
{
assert(Q);
QListNode* tmp = (QListNode*)malloc(sizeof(QListNode));
tmp->next = NULL;
tmp->data = x;
if (Q->phead == NULL)
{
Q->phead = Q->ptail = tmp;
}
else
{
Q->ptail->next = tmp;
Q->ptail = Q->ptail->next;
}
Q->size++;
}
void QPop(QList* Q)
{
assert(Q);
if (QEmpety(Q))
{
return;
}
if (Q->phead == Q->ptail)
{
free(Q->phead);
Q->phead = Q->ptail = NULL;
}
else
{
QListNode* tmp = Q->phead;
Q->phead = Q->phead->next;
free(tmp);
tmp = NULL;
}
Q->size--;
}
QListDataNode QFront(QList* Q)
{
assert(Q);
return Q->phead->data;
}
QListDataNode QBack(QList* Q)
{
assert(Q);
return Q->ptail->data;
}
int QSize(QList* Q)
{
assert(Q);
return Q->size;
}
int QEmpety(QList* Q)
{
assert(Q);
return Q->size == 0;
}
int main()
{
QList Q;
QInit(&Q);
QPush(&Q, 1);
QPush(&Q, 2);
QPush(&Q, 3);
QPush(&Q, 4);
QPush(&Q, 5);
while (!QEmpety(&Q))
{
printf("%d %d\n", QFront(&Q), QSize(&Q));
QPop(&Q);
}
QDestory(&Q);
return 0;
}
通过本文的介绍,读者应该对队列的概念、特性、实现方式以及在C语言中的应用有了更深入的了解。队列作为一种重要的数据结构,在算法和系统设计中具有广泛的应用。掌握队列的原理和基本操作,将有助于读者更好地理解和应用队列这一重要数据结构。
参考资料:
- GeeksforGeeks - Queue Data Structure: Queue Data Structure - GeeksforGeeks