Files
list/src/lib/queue/queue.c

296 lines
6.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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 遍历队列
*
* @param queue
* @param func 回调函数 指定了数据(未指定数据类型)和索引
*/
void queue_foreach(const queue_t *queue, void (*func)(void *data, size_t index)) {
queue_node_t *node = queue->head;
size_t idx = 0;
while (node) {
func(node->data, idx);
node = node->next;
idx++;
}
}
/**
* @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);
// 如果有其他资源分配,可在此释放
}