280 lines
6.1 KiB
C
280 lines
6.1 KiB
C
|
/**
|
|||
|
* @file queue.c
|
|||
|
* @author guishenking (guishenking@outlook.com)
|
|||
|
* @brief
|
|||
|
* @version 0.1
|
|||
|
* @date 2025-08-14
|
|||
|
*
|
|||
|
* @copyright Copyright (c) 2025
|
|||
|
*
|
|||
|
*/
|
|||
|
#include "queue.h"
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 初始化队列
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
* @param elem_size 数据类型大小
|
|||
|
*/
|
|||
|
bool queue_init(queue_t *queue, size_t elem_size) {
|
|||
|
queue->head = NULL;
|
|||
|
queue->tail = NULL;
|
|||
|
queue->size = 0;
|
|||
|
if(elem_size == 0) {
|
|||
|
return false; // 元素大小不能为0
|
|||
|
}
|
|||
|
queue->elem_size = elem_size;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 入队
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
* @param value
|
|||
|
* @return true
|
|||
|
* @return false
|
|||
|
*/
|
|||
|
bool queue_enqueue(queue_t *queue, const void *value) {
|
|||
|
// 分配新节点
|
|||
|
if (queue->size >= QUEUE_MAX_SIZE) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
queue_node_t *node = (queue_node_t *)malloc(sizeof(queue_node_t));
|
|||
|
if (!node) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
// 分配数据空间并复制数据
|
|||
|
node->data = malloc(queue->elem_size);
|
|||
|
// 检查数据分配是否成功
|
|||
|
if (!node->data) {
|
|||
|
// 数据分配失败,此时node还未加入链表,只需释放node本身即可
|
|||
|
free(node);
|
|||
|
return false;
|
|||
|
}
|
|||
|
// 复制数据到节点
|
|||
|
memcpy(node->data, value, queue->elem_size);
|
|||
|
// 将下一级节点添加到队列
|
|||
|
node->next = NULL;
|
|||
|
// 如果队列为空,设置头尾指针
|
|||
|
if (queue->tail) {
|
|||
|
// 如果队列不为空,将新节点添加到尾部
|
|||
|
queue->tail->next = node;
|
|||
|
} else {
|
|||
|
// 如果队列为空,将新节点设置为头部
|
|||
|
queue->head = node;
|
|||
|
}
|
|||
|
// 更新尾部指针并增加队列大小
|
|||
|
queue->tail = node;
|
|||
|
queue->size++;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 从队列头部出队
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
* @param value
|
|||
|
* @return true
|
|||
|
* @return false
|
|||
|
*/
|
|||
|
bool queue_dequeue_head(queue_t *queue, void *value) {
|
|||
|
// 检查队列是否为空
|
|||
|
if (queue->size == 0) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
queue_node_t *node = queue->head;
|
|||
|
// 复制头部数据到输出参数
|
|||
|
memcpy(value, node->data, queue->elem_size);
|
|||
|
// 更新头部指针
|
|||
|
queue->head = node->next;
|
|||
|
// 如果头部为空,更新尾部指针
|
|||
|
if (!queue->head) {
|
|||
|
queue->tail = NULL;
|
|||
|
}
|
|||
|
// 释放节点和数据
|
|||
|
free(node->data);
|
|||
|
free(node);
|
|||
|
queue->size--;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 从队列尾部出队
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
* @param value
|
|||
|
* @return true
|
|||
|
* @return false
|
|||
|
*/
|
|||
|
bool queue_dequeue_tail(queue_t *queue, void *value) {
|
|||
|
if (queue->size == 0) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
queue_node_t *prev = NULL;
|
|||
|
queue_node_t *node = queue->head;
|
|||
|
// 找到最后一个节点
|
|||
|
while (node && node->next) {
|
|||
|
prev = node;
|
|||
|
node = node->next;
|
|||
|
}
|
|||
|
memcpy(value, node->data, queue->elem_size);
|
|||
|
if (prev) {
|
|||
|
prev->next = NULL;
|
|||
|
queue->tail = prev;
|
|||
|
} else {
|
|||
|
// 只有一个节点
|
|||
|
queue->head = NULL;
|
|||
|
queue->tail = NULL;
|
|||
|
}
|
|||
|
free(node->data);
|
|||
|
free(node);
|
|||
|
queue->size--;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 查询队列指定位置的数据
|
|||
|
*
|
|||
|
* @param queue 队列指针
|
|||
|
* @param index 位置(0为头部)
|
|||
|
* @param value 输出数据指针
|
|||
|
* @return true 查询成功
|
|||
|
* @return false 越界或队列为空
|
|||
|
*/
|
|||
|
bool queue_peek_at(const queue_t *queue, size_t index, void *value) {
|
|||
|
if (index >= queue->size || queue->size == 0) {
|
|||
|
return false; // 越界或队列为空
|
|||
|
}
|
|||
|
queue_node_t *node = queue->head;
|
|||
|
for (size_t i = 0; i < index; ++i) {
|
|||
|
node = node->next;
|
|||
|
}
|
|||
|
memcpy(value, node->data, queue->elem_size);
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 抛弃队列前n个数据
|
|||
|
*
|
|||
|
* @param queue 队列指针
|
|||
|
* @param n 要抛弃的元素数量
|
|||
|
* @return size_t 实际抛弃的元素数量
|
|||
|
*/
|
|||
|
size_t queue_drop_head(queue_t *queue, size_t n) {
|
|||
|
size_t dropped = 0;
|
|||
|
if (n == 0 || queue->size == 0) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
if (n >= queue->size) {
|
|||
|
dropped = queue->size;
|
|||
|
queue_clear(queue);
|
|||
|
return dropped;
|
|||
|
}
|
|||
|
while (dropped < n && queue->size > 0) {
|
|||
|
queue_node_t *node = queue->head;
|
|||
|
queue->head = node->next;
|
|||
|
free(node->data);
|
|||
|
free(node);
|
|||
|
queue->size--;
|
|||
|
dropped++;
|
|||
|
}
|
|||
|
if (!queue->head) {
|
|||
|
queue->tail = NULL;
|
|||
|
}
|
|||
|
return dropped;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 抛弃队列尾部n个数据
|
|||
|
*
|
|||
|
* @param queue 队列指针
|
|||
|
* @param n 要抛弃的元素数量
|
|||
|
* @return size_t 实际抛弃的元素数量
|
|||
|
*/
|
|||
|
size_t queue_drop_tail(queue_t *queue, size_t n) {
|
|||
|
size_t dropped = 0;
|
|||
|
if (n == 0 || queue->size == 0) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
if (n >= queue->size) {
|
|||
|
// 清空整个队列
|
|||
|
dropped = queue->size;
|
|||
|
queue_clear(queue);
|
|||
|
return dropped;
|
|||
|
}
|
|||
|
for (size_t i = 0; i < n; ++i) {
|
|||
|
queue_node_t *prev = NULL;
|
|||
|
queue_node_t *node = queue->head;
|
|||
|
// 找到最后一个节点
|
|||
|
while (node && node->next) {
|
|||
|
prev = node;
|
|||
|
node = node->next;
|
|||
|
}
|
|||
|
if (!node) break;
|
|||
|
if (prev) {
|
|||
|
prev->next = NULL;
|
|||
|
queue->tail = prev;
|
|||
|
} else {
|
|||
|
// 只有一个节点
|
|||
|
queue->head = NULL;
|
|||
|
queue->tail = NULL;
|
|||
|
}
|
|||
|
free(node->data);
|
|||
|
free(node);
|
|||
|
queue->size--;
|
|||
|
dropped++;
|
|||
|
}
|
|||
|
return dropped;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 判断队列是否为空
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
* @return true
|
|||
|
* @return false
|
|||
|
*/
|
|||
|
bool queue_is_empty(const queue_t *queue) {
|
|||
|
return queue->size == 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 获取队列长度
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
* @return size_t
|
|||
|
*/
|
|||
|
size_t queue_length(const queue_t *queue) {
|
|||
|
return queue->size;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 清空队列
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
*/
|
|||
|
void queue_clear(queue_t *queue) {
|
|||
|
queue_node_t *node = queue->head;
|
|||
|
while (node) {
|
|||
|
queue_node_t *next = node->next;
|
|||
|
free(node->data);
|
|||
|
free(node);
|
|||
|
node = next;
|
|||
|
}
|
|||
|
queue->head = NULL;
|
|||
|
queue->tail = NULL;
|
|||
|
queue->size = 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 销毁队列
|
|||
|
*
|
|||
|
* @param queue
|
|||
|
*/
|
|||
|
void queue_destroy(queue_t *queue) {
|
|||
|
queue_clear(queue);
|
|||
|
// 如果有其他资源分配,可在此释放
|
|||
|
}
|