基于C语言的泛类型循环队列

文章介绍了在中低端MCU环境下,如何使用顺序表实现泛类型的循环队列,以适应不同数据类型的存储需求。通过初始化时指定节点字节数,并利用memcpy进行数据拷贝,实现了高效且灵活的数据入队和出队操作。同时,提供了包括初始化、入队、出队、判空、判满等接口函数的代码示例。
摘要由CSDN通过智能技术生成

循环队列多用于通信数据缓存中,尤其是在双方设备接收数据与处理数据不同步的情况下,使用循环队列先缓存通信数据,然后按照时间戳数据出队作出相应的处理,是一种比较合适的做法,在嵌入式编程中亦是如此。使用循环队列的数据结构可以实现上述功能,在一些低端的编程平台手写一个循环队列既满足了功能需求又不会开销太多资源。

设计思想

实现一个队列可以使用顺序表(数组)或链表实现。前者访问速度块,但是要占用连续的存储空间,适用于内存小但是速度要求较快的存储场合。后者访问速度慢但是基于链表式的结构,可以使用碎片内存,适用内存大,速度慢的场合。本文面向的编程平台是中低端MCU,时钟主频、RAM空间有限,因此选用顺序表来实现循环队列。
关于顺序表实现循环队列的文章网上又很多,但是大多都基于一个明确的数据类型,如果在一个工程中两种完全不同的数据类型都想使用循环队列的数据结构就会使得相同的代码出现多次,导致代码冗余。
泛类型循环队列的思想是将顺序表中每个节点都看作一个uint8_t*类型的指针,在队列初始化时,要传入节点占用空间字节数,对每个节点malloc一个相应的存储空间,当数据入队时使用memcpy函数将源地址字节数拷贝到目标地址即可,队列数据表的结构有点类似于哈希表,操作与定类型循环队列类似。

代码实现

队列实现包含两个文件:queue.h和queue.c
queue.h:
使用枚举自定义BOOL类型,C99标准之后包含stdbool.h可使用标准布尔型

 typedef enum
 {
    FALSE,
    TRUE
 } BOOL;

宏定义顺序表中的节点类型

#define NODTETYPE uint8_t*

定义循环队列结构体

typedef struct Queue
{
	uint32_t capacity;     // 队列总容量
	uint32_t size;         // 当前队列大小
	uint32_t front;        // 队列头节点
	uint32_t rear;         // 队列尾节点
  NODTETYPE* data;         //存储节点的顺序表
} Queue;

接口函数

/* 初始化一个队列 */
BOOL init_queue(Queue *queue,uint32_t _capacity,uint32_t DataWidth);
/* 数据入队 */
BOOL en_queue(Queue* _queue, NODTETYPE _data,uint32_t DataWidth);
/*队列判空*/
BOOL isempty_queue(Queue* _queue);
/*队列判满*/
BOOL isfull_queue(Queue* _queue);
/* 数据出队 */
NODTETYPE de_queue(Queue* _queue);
/* 清空队列 */
void clear_queue(Queue* _queue);

queue.c
队列初始化,此处必须传入节点的数据占用字节数DataWidth,注意可用队列容量总是比传入参数_capacity小一,因为要判空和判满。

BOOL init_queue(Queue *queue,uint32_t _capacity,uint32_t DataWidth)
{
    NODTETYPE *buff= (NODTETYPE*)malloc(_capacity*sizeof(NODTETYPE));
    if(buff==NULL)
        return FALSE;
    for(int i=0;i<_capacity;i++)
    {
        NODTETYPE NodeTemp=(NODTETYPE)malloc(DataWidth);
        if(NodeTemp==NULL)
            return FALSE;
        else
            buff[i]=NodeTemp;
    }
    queue->data=buff;
    queue->capacity = _capacity;
    queue->size = 0;
    queue->front = 0;  
    queue->rear = 0;
    return TRUE;
}

数据节点入队

BOOL en_queue(Queue* _queue, NODTETYPE _data,uint32_t DataWidth)
{
    BOOL isFull;
    isFull = isfull_queue(_queue);
    if (isFull == TRUE)
    {
        _queue->front = (_queue->front + 1) % _queue->capacity;
    }
    memcpy(_queue->data[_queue->rear], _data,DataWidth);
    _queue->rear = (_queue->rear + 1) % _queue->capacity;
    _queue->size++;
    return isFull;
}

数据节点出队

NODTETYPE de_queue(Queue* _queue)
{
    if (isempty_queue(_queue))
         return NULL;
    NODTETYPE result = _queue->data[_queue->front];
    _queue->front = (_queue->front + 1) % _queue->capacity;
    _queue->size--;
    return result;
}

队列清空,但是不释放存储空间

void clear_queue(Queue* _queue)
{
    _queue->front = _queue->rear = 0;
    _queue->size = 0;
}

队列判空

BOOL isempty_queue(Queue* _queue)
{
	if (_queue->front == _queue->rear)
		return TRUE;
	else
		return FALSE;
}

队列判满

BOOL isfull_queue(Queue* _queue)
{
	if ((_queue->rear + 1) % _queue->capacity == _queue->front)
		return TRUE;
	else
		return FALSE;
}

队列清空并释放内存

void release_queue(Queue* _queue)
{
    for(int i=0;i<_queue->capacity;i++)
    {
        free(_queue->data[i]);
        _queue->data[i]=NULL;
    }
    clear_queue(_queue);
    free(_queue);
    _queue = NULL;
}

调用时入队时,要先将节点数据类型强制转化为uint8_t类型,传入形参,出队时获取一个uint8_t的指针,然后强制转换为定义的节点类型指针,之后就可以访问到出队节点的数据,举例如下:

#include "queue.h"
typedef  struct ClassTest  //定义测试类型
{
    uint8_t a;
    uint16_t b;
    uint32_t c;
}ClassTest;
int main(int argc, char *argv[])
{
    Queue queue1;
    Queue queue2;
    init_queue(&queue1,100,sizeof (ClassTest));
    init_queue(&queue2,200,1);  //测试队列2就用uint8_t
    int i=0;
    uint8_t queue1_node=0;
    ClassTest queue2_node={0,0,0};
    while(isfull_queue(&queue1)==FALSE)
    {
        queue1_node=i++;
        en_queue(&queue1,&queue1_node,sizeof (queue1_node));
    }
    i=0;
    while(isfull_queue(&queue2)==FALSE)
    {
        queue2_node.a=i++;
        queue2_node.b=2*i;
        en_queue(&queue2,(uint8_t*)(&queue2_node),sizeof (queue2_node));
    }
    while(isempty_queue(&queue1)==FALSE)
    {
        NODTETYPE node=de_queue(&queue1);
        printf("%d;",*((uint8_t*)(node)));
    }
    while(isempty_queue(&queue2)==FALSE)
    {
        NODTETYPE node=de_queue(&queue2);
        prinf("%d;",((ClassTest*)(node))->b);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值