C语言实现队列

一、队列的概念

1.定义

队列,是一种先进先出(first in first out 简称FIFO)的数据结构,是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,在队列中,进行插入的一端称为队尾,进行删除的一端称为队头。

队列也可以分为顺序队列(基于数组实现)和链队列(基于链表实现)。

2.队列的应用

缓冲:

队列可以用来缓冲输入和输出操作,平衡生产者和消费者之间的速度差异。例如,在Web服务器中,当多个请求同时到达时,可以将这些请求放入队列中,然后服务器按顺序处理这些请求。

任务调度:

在多任务或多线程系统中,队列可以用来安排任务的执行顺序。任务被添加到队列中,然后根据优先级或到达顺序被调度执行。

同步:

在多线程编程中,队列可以用来实现线程间的同步和数据传递。一个线程可以将数据放入队列中,另一个线程则从队列中取出数据,从而实现了数据的同步传输。

二、队列的相关操作

初始化队列:创建一个新的空队列的过程。

        

销毁队列:释放队列使用的资源并使队列不再可用的过程。

        

入队:将一个元素添加到队列。    

出队:弹出队头元素。

取队头元素:得到队头元素,但是不改变原队列。

取队尾元素:得到队尾元素,但是不改变原队列。

判断队列是否为空:判断队列里面有没有元素。

求队列的大小 :返回队列中元素的数量。

三、队列的实现

    队列也可以数组和链表的结构实现,但使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率比较低。又因为只在队头和队尾进行操作,因此使用单链表即可。

为了能够灵活使用,不浪费空间 ,因此使用动态队列。在插入元素时会自动进行扩容。

    

1.定义队列的结构

typedef int DataType; 是C语言中的类型定义(typedef)语句,用于创建一个新的类型名称。在这里它定义了 DataType 作为 int 类型的别名,也就是在队列中存储整型,如果想存储其他类型的数据,改变int为其他类型即可。

QNode 结构体:这是队列中节点的定义,包含了两个部分:

DataType data:数据域,存储队列中的数据。

struct QueueNode* next:指针域,指向队列中下一个节点。

Que 结构体:这是队列的主体结构,包含了三个部分:

QNode* head:头指针,指向队列的第一个元素。

QNode* tail:尾指针,指向队列的最后一个元素。

int size:队列的大小,即队列中元素的数量。

typedef int DataType;

//队列的结构体

typedef struct QueueNode

{

DataType data;

//数据域

struct QueueNode* next;

//指针域

}QNode;

typedef struct Queue

{

QNode* head;

//头指针

QNode* tail;

//尾指针

int size;

//队列的大小

}Que;

2.初始化队列

assert(q):使用 assert 函数来确保传入的队列指针 q 不是 NULL。确保这个队列正确存在,在后面也会多次使用。

我们需要以下步骤:

1、初始化头尾指针

2、初始化队列大小

void QueueInit(Que* q)

{

assert(q);

q->head = q->tail = NULL;

//初始化头指针和尾指针

q->size = 0;

//初始化队列大小为0

}

3.入队

向队列中添加一个新元素。我们需要分为两种情况,一种是队列为空,另一种是队列不为空。

我们需要以下步骤:

内存申请:为新节点分配内存,若申请失败则打印错误并退出。

设置数据和指针:将传入的数据赋给新节点的数据域,将新节点的下一个指针设置为 NULL。

更新队列指针:队列为空,则新节点同时作为头节点和尾节点。队列不为空,则添加到尾部并更新尾指针。

更新队列大小:队列大小加1。

void QueuePush(Que* q, DataType x)

{

assert(q);

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

//申请新节点空间

if (newnode == NULL)

{

perror("malloc fail");

exit(-1);

}

newnode->data = x;

newnode->next = NULL;

//如果队列为空

if (q->tail == NULL)

{

q->head=q->tail = newnode;

}

//如果队列不为空

else

{

q->tail->next = newnode;

q->tail = newnode;

}

q->size++;

}

4.出队

从队列中移除一个元素。同样分为两种情况,一种是队列为空,另一种是队列不为空。

我们需要以下步骤:

断言检查:确保队列不为空。

释放头节点:如果队列只有一个元素,则直接释放该元素,如果队列有多个元素,则释放头节点。

更新队列指针和大小:如果队列只有一个元素,同时更新尾指针,如果队列有多个元素,则更新头指。队列大小减1。

void QueuePop(Que* q)

{

assert(q);

assert(!QueueEmpty(q));

//如果队列只有一个元素

if (q->head->next == NULL)

{

free(q->head);

q->head = q->tail = NULL;

}

//如果队列有多个元素

else

{

QNode* next = q->head->next;

free(q->head);

q->head = next;

}

q->size--;

}

5.取队头元素、 取队尾元素

要求队列非空,返回队列的第一个元素的值或者最后一个函数值,因为有头尾指针,因此很简单,只需要直接返回即可。

我们需要以下步骤:

断言检查:确保队列不为空。

返回值:返回头节点或尾节点的数据。

//头节点元素

DataType QueueFront(Que* q)

{

assert(q);

assert(!QueueEmpty(q));

return q->head->data;

}

//尾节点元素

DataType QueueBack(Que* q)

{

assert(q);

assert(!QueueEmpty(q));

return q->tail->data;

}

6.判断队列是否为空、求队列元素个数

如果队列的大小为0,则返回 true。因为有size,直接返回队列大小是否为0的比较结果就行。获取元素个数就直接返回size个数就行。

这里注意,bool需要引入头文件#include<stdbool.h>

//判断队列是否为空

bool QueueEmpty(Que* q)

{

assert(q);

return q->size == 0;

}

//求队列元素个数

int QueueSize(Que* q)

{

assert(q);

return q->size;

}

7.销毁队列

因为是单链表实现,销毁队列需要释放队列中所有节点的内存,并将队列的头、尾指针以及大小重置。

我们需要以下步骤:

断言检查:确保传入的队列指针不是 NULL。

遍历释放:从头节点开始,遍历每个节点,并释放其内存。

重置指针和大小:将头指针、尾指针设置为 NULL,队列大小设置为0,表示队列为空并且没有内存泄漏。

void QueueDestroy(Que* q)

{

assert(q);

QNode* cur = q->head;

//从头指针开始释放

while (cur)

{

//保存下一个节点的地址

QNode* next = cur->next;

//释放当前节点

free(cur);

//更新当前节点

cur = next;

}

q->head = q->tail = NULL;

q -> size = 0;

}

四、完整代码

1.Queue.h :

#pragma once

#include<stdio.h>

#include<stdlib.h>

#include<stdbool.h>

#include<assert.h>

typedef int DataType;

//队列的结构体

typedef struct QueueNode

{

DataType data;

//数据域

struct QueueNode* next;

//指针域

}QNode;

typedef struct Queue

{

QNode* head;

//头指针

QNode* tail;

//尾指针

int size;

//队列的大小

}Que;

//初始化

void QueueInit(Que* q);

//销毁

void QueueDestroy(Que* q);

//入队

void QueuePush(Que* q,DataType x);

//出队

void QueuePop(Que* q);

//取队首元素

DataType QueueFront(Que* q);

//取队尾元素

DataType QueueBack(Que* q);

//判断队列是否为空

bool QueueEmpty(Que* q);

//求队列的大小

int QueueSize(Que* q);

2.Queue.c:

#include"Queue.h"

//队列初始化

void QueueInit(Que* q)

{

assert(q);

q->head = q->tail = NULL;

//初始化头指针和尾指针

q->size = 0;

//初始化队列大小为0

}

//销毁队列

void QueueDestroy(Que* q)

{

assert(q);

QNode* cur = q->head;

//从头指针开始释放

while (cur)

{

//保存下一个节点的地址

QNode* next = cur->next;

//释放当前节点

free(cur);

//更新当前节点

cur = next;

}

q->head = q->tail = NULL;

q -> size = 0;

}

//入队

void QueuePush(Que* q, DataType x)

{

assert(q);

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

//申请新节点空间

if (newnode == NULL)

{

perror("malloc fail");

exit(-1);

}

newnode->data = x;

newnode->next = NULL;

//如果队列为空

if (q->tail == NULL)

{

q->head=q->tail = newnode;

}

//如果队列不为空

else

{

q->tail->next = newnode;

q->tail = newnode;

}

q->size++;

}

//出队

void QueuePop(Que* q)

{

assert(q);

assert(!QueueEmpty(q));

//如果队列只有一个元素

if (q->head->next == NULL)

{

free(q->head);

q->head = q->tail = NULL;

}

//如果队列有多个元素

else

{

QNode* next = q->head->next;

free(q->head);

q->head = next;

}

q->size--;

}

//取队首元素

DataType QueueFront(Que* q)

{

assert(q);

assert(!QueueEmpty(q));

return q->head->data;

}

//取队尾元素

DataType QueueBack(Que* q)

{

assert(q);

assert(!QueueEmpty(q));

return q->tail->data;

}

//判断队列是否为空

bool QueueEmpty(Que* q)

{

assert(q);

return q->size == 0;

}

//求队列元素个数

int QueueSize(Que* q)

{

assert(q);

return q->size;

}

3.test.c:

#include"Queue.h"

void test()

{

Que qp ;

QueueInit(&qp);

QueuePush(&qp, 1);

QueuePush(&qp, 2);

QueuePush(&qp, 3);

QueuePush(&qp, 4);

QueuePush(&qp, 5);

QueuePush(&qp, 6);

printf("入队1-6\n");

printf("头元素:");

printf("%d\n",QueueFront(&qp));

printf("尾元素:");

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

printf("\n");

QueuePush(&qp, 7);

printf("入队7\n");

printf("头元素:");

printf("%d\n", QueueFront(&qp));

printf("尾元素:");

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

printf("\n");

QueuePush(&qp, 8);

printf("入队8\n");

printf("头元素:");

printf("%d\n", QueueFront(&qp));

printf("尾元素:");

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

printf("\n");

QueuePop(&qp);

printf("出队\n");

printf("头元素:");

printf("%d\n", QueueFront(&qp));

printf("尾元素:");

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

printf("\n");

printf("出队\n");

QueuePop(&qp);

printf("头元素:");

printf("%d\n", QueueFront(&qp));

printf("尾元素:");

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

QueueDestroy(&qp);

}

int main()

{

test();

return 0;

}

参考文章:https://blog.csdn.net/2302_77041624/article/details/138748164

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ZeroMQ的C语言实现是通过使用C语言库czmq来实现队列功能的。czmq是ZeroMQ的一个高级封装库,它提供了一组易于使用的API,用于在生产者和消费者之间建立队列通信。 使用ZeroMQ的C语言实现队列的主要特点是,不需要搭建队列环境,只需引入czmq库,并在生产者和消费者代码中调用相应的API即可。与传统的BSD开发不同,ZeroMQ中的Server和Client启动顺序没有要求。这意味着先启动Server还是先启动Client并不影响队列的正常运行。 总结起来,通过引入czmq库,并调用相应的API,ZeroMQ的C语言实现提供了一种简单而灵活的方法来实现队列功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [消息队列zeromq的c语言安装包czmq-4.2.1版本](https://download.csdn.net/download/weixin_41803458/85046594)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [转载 消息队列ZeroMQ C语言](https://blog.csdn.net/wc996789331/article/details/104404412)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI+程序员在路上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值