队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
队列在应用开发中经常会使用到,常见的队列有链式队列和循环队列,具体的原理我这里就不详细解析了,感兴趣的同学可以自行查阅资料。
我这里主要使用C语言实现一个通用的循环队列,示意图如下:
先划分一块缓存用来存放队列的数据,然后通过头指针和尾指针,分别指向队列的第一个元素和最后一个元素,当数据入队时,尾指针后移,当数据出队时,头指针后移,从而实现一个闭环。
注:队列中的元素并不是某个特定类型的变量,它可以是整形,可以是数组,也可以是结构体,也就是说这是一个通用的框架。
队列实现定义(h文件):
#ifndef __QUEUE_H_
#define __QUEUE_H_
/*********************************************************************
* @brief 队列类型定义
*********************************************************************/
typedef struct
{
volatile unsigned int front; // front为起始元素
volatile unsigned int rear; // rear为最后一个元素
volatile unsigned int count; // 元素个数
unsigned int element_size; // 每个元素的字节数(这里的元素可以是任意类型的变量)
unsigned int element_num; // 队列深度(元素最大个数,以元素的类型为基本单位,例如元素是结构体,那element_num就是这个结构体的数量)
void *buf; // 缓存区(大小为element_size * element_num)
}queue_type;
/*********************************************************************
* @brief 队列初始化
* @param[in] queue: 队列指针
* @param[in] buf: 队列中缓存
* @param[in] element_size:队列每个元素的字节数
* @param[in] element_num: 队列深度(元素最大个数)
* @return None
*********************************************************************/
void queue_create(queue_type *queue, void *buf, unsigned int element_size, unsigned int element_num);
/*********************************************************************
* @brief 判断队列是否为空
* @param[in] queue: 队列指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char queue_is_empty(queue_type *queue);
/*********************************************************************
* @brief 判断队列是否已满
* @param[in] queue: 队列指针
* @return TRUE or FALSE
*********************************************************************/
unsigned char queue_is_full(queue_type *queue);
/*********************************************************************
* @brief 向队列添加一个元素
* @param[in] queue: 队列指针
* @param[in] value: 要添加的元素
*********************************************************************/
unsigned char queue_append_byte(queue_type *queue, void *value);
/*********************************************************************
* @brief 向队列添加多个元素
* @param[in] queue: 队列指针
* @param[in] values: 要添加的元素指针
* @param[in] element_num: 要添加元素个数
* @return 实际添加的元素个数
*********************************************************************/
unsigned int queue_append_nbyte(queue_type *queue, void *values, unsigned int element_num);
/*********************************************************************
* @brief 从队列读取一个元素
* @param[in] queue: 队列指针
* @param[in] value: 存放要读取的元素指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char queue_delete_byte(queue_type *queue, void *value);
/*********************************************************************
* @brief 从队列读取多个元素
* @param[in] queue: 队列指针
* @param[out] values: 存放要读取的元素指针
* @param[in] element_num: 要读取的元素个数
* @return 实际读取的元素个数
*********************************************************************/
unsigned int queue_delete_nbyte(queue_type *queue, void *values, unsigned int element_num);
/*********************************************************************
* @brief 清空队列
* @param[in] queue: 队列指针
* @return None
*********************************************************************/
void queue_clear(queue_type *queue);
#endif
队列实现代码(c文件):
#include
#include "queue.h"
#include
/*********************************************************************
* @brief 创建队列
* @param[in] queue: 队列指针
* @param[in] buf: 队列缓存(大小为element_size * element_num)
* @param[in] element_size: 队列每个元素的大小(这里的元素可以是任意类型的变量)
* @param[in] element_num: 队列最大元素个数(以元素的类型为基本单位,例如元素是一个结构体,那么element_num就是这个结构体的数量)
* @return None
*********************************************************************/
void queue_create(queue_type *queue, void *buf, unsigned int element_size, unsigned int element_num)
{
queue->buf = buf;
queue->element_size = element_size;
queue->element_num = element_num;
queue->front = 0;
queue->rear = 0;
queue->count = 0;
}
/*********************************************************************
* @brief 判断队列是否为空
* @param[in] queue: 队列指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char queue_is_empty(queue_type *queue)
{
return (queue->count == 0);
}
/*********************************************************************
* @brief 判断队列是否已满
* @param[in] queue: 队列指针
* @return TRUE or FALSE
*********************************************************************/
unsigned char queue_is_full(queue_type *queue)
{
return (queue->count == queue->element_num);
}
/*********************************************************************
* @brief 向队列添加一个元素
* @param[in] queue: 队列指针
* @param[in] value: 要添加的元素
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char queue_append_byte(queue_type *queue, void *value)
{
unsigned char *p;
if (queue_is_full(queue))
{
return 0;
}
p = (unsigned char *)queue->buf;
memcpy(p + queue->rear, (unsigned char *)value, queue->element_size);
queue->rear += queue->element_size;
if (queue->rear >= queue->element_size * queue->element_num)
{
queue->rear = 0;
}
queue->count ++;
return 1;
}
/*********************************************************************
* @brief 向队列添加多个元素
* @param[in] queue: 队列指针
* @param[in] values: 要添加的元素指针
* @param[in] element_num: 要添加的元素个数
* @return 实际添加的元素个数
*********************************************************************/
unsigned int queue_append_nbyte(queue_type *queue, void *values, unsigned int element_num)
{
unsigned char *p;
unsigned int cnt = 0;
p = (unsigned char *)values;
while(element_num --)
{
if (queue_append_byte(queue, p))
{
p += queue->element_size;
cnt++;
}
else
{
break;
}
}
return cnt;
}
/*********************************************************************
* @brief 从队列读取一个元素
* @param[in] queue: 队列指针
* @param[in] value: 存放要读取的元素指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char queue_delete_byte(queue_type *queue, void *value)
{
unsigned char *p;
if (queue_is_empty(queue))
{
return 0;
}
p = (unsigned char *)queue->buf;
memcpy(value, p + queue->front, queue->element_size);
queue->front += queue->element_size;
if (queue->front >= queue->element_size * queue->element_num)
{
queue->front = 0;
}
queue->count --;
return 1;
}
/*********************************************************************
* @brief 从队列读取多个元素
* @param[in] queue: 队列指针
* @param[out] values: 存放要读取的元素指针
* @param[in] element_num: 要读取的元素长度
* @return 实际读取的元素个数
*********************************************************************/
unsigned int queue_delete_nbyte(queue_type *queue, void *values, unsigned int element_num)
{
unsigned int cnt = 0;
unsigned char *p;
p = values;
while(element_num--)
{
if (queue_delete_byte(queue, p))
{
p += queue->element_size;
cnt++;
}
else
{
break;
}
}
return cnt;
}
/*********************************************************************
* @brief 清空队列
* @param[in] queue: 队列指针
* @return None
*********************************************************************/
void queue_clear(queue_type *queue)
{
queue->count = 0;
queue->front = 0;
queue->rear = 0;
}
使用示例:
/* 元素为char类型 */
queue_type queue; // 新建队列
char queue_buf[50]; // 队列缓存区,存放50个元素
char test_data1 = 1; // 测试入队字符
char test_data2; // 测试出队字符
queue_create(&queue, queue_buf, 1, 50); // 创建1个队列,每个元素大小为1byte,队列长度为50byte
queue_append_byte(&queue, &test_data1); // 入队1个字符
queue_delete_byte(&queue, &test_data2); // 出队1个字符
/* 元素为数组类型 */
queue_type queue; // 新建队列
uint8_t queue_buf[5*10]; // 队列缓存区,存放10个元素,每个元素为5byte的数组
uint8_t test_buf1[5] = {1, 2, 3, 4, 5}; // 测试入队数组
uint8_t test_buf2[5]; // 测试出队数组
queue_create(&queue, queue_buf, 5, 10); // 创建1个队列,每个元素大小为5byte,队列长度为10
queue_append_byte(&queue, &test_buf1); // 入队1个数组
queue_delete_byte(&queue, &test_buf2); // 出队1个数组
/* 元素为结构体类型 */
queue_type queue; // 新建队列
typedef struct
{// 测试结构体类型
uint8_t addr;
uint8_t data;
} test_param_t;
test_param_t queue_buf[10]; // 队列缓存区,存放10个元素,每个元素为结构体queue_buf的大小
test_param_t test_buf1 = {1, 2}; // 测试入队结构体
test_param_t test_buf2; // 测试出队结构体
queue_create(&queue, queue_buf, sizeof(test_param_t), 10); // 创建1个队列,元素为queue_buf大小(2byte),队列长度为10
queue_append_byte(&queue, &test_buf1); // 入队1个结构体
queue_delete_byte(&queue, &test_buf2); // 出队1个结构体
我这里用循环队列做了一个通用框架,这种方式的好处是同一套代码可以用在各种自定义变量上面,只需要在初始化的时候,设置好这个队列的元素类型和长度即可。当然,我这里只是列举了一种方式,实际上还有很多方法实现。
好了,关于使用C语言实现队列的方法就介绍到这里,如果你们有什么问题,欢迎评论区留言。
如果这篇文章能够帮到你,就…懂的。