Initial commit: my SECS2 project
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
#include "algo_queue.h"
|
||||
|
||||
/* 计算队列中第i个元素的地址 */
|
||||
#define at(i) (((char *)(queue->base))+(i)*(queue->dsize))
|
||||
/* 数据赋值:将源地址s的数据复制到目标地址d */
|
||||
#define assign(d, s) memcpy((d), (s), queue->dsize)
|
||||
/* 获取队列中逻辑位置i的元素地址(考虑循环队列) */
|
||||
#define qa(i) at((queue->head + queue->capacity + (i)) % (queue->capacity))
|
||||
|
||||
/* 简易内存复制函数 */
|
||||
static void* memcpy(void* dest, const void* src, int n)
|
||||
{
|
||||
char* dst = dest;
|
||||
const char* s = src;
|
||||
while (n--) *dst++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* 将队列中从index开始的size个元素向前移动一位 */
|
||||
static void move_forward(queue queue, int index, int size)
|
||||
{
|
||||
for (int i = index; i < index + size; i++) assign(qa(i - 1), qa(i));
|
||||
}
|
||||
|
||||
/* 将队列中从index开始的size个元素向后移动一位 */
|
||||
static void move_backward(queue queue, int index, int size)
|
||||
{
|
||||
for (int i = index + size; i > index; i--) assign(qa(i), qa(i - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 标准入队操作(队尾添加)
|
||||
* \param[in] queue: 队列对象指针
|
||||
* \param[in] data: 待添加数据地址(NULL表示仅移动指针)
|
||||
* \return 1=成功, 0=失败(队列无效或已满)
|
||||
*
|
||||
* \details 在队列尾部添加新元素。如果队列已满则操作失败。
|
||||
* 当data不为NULL时,将数据复制到队列存储区。
|
||||
* 更新尾指针和队列大小。
|
||||
*/
|
||||
int queue_push(queue queue, void* data)
|
||||
{
|
||||
if (!queue) return 0; // 检查队列指针有效性
|
||||
if (queue->size == queue->capacity) return 0; // 队列已满
|
||||
if (data) assign(at(queue->tail), data); // 数据复制到队尾
|
||||
queue->tail = (queue->tail + 1) % queue->capacity; // 更新尾指针(循环)
|
||||
queue->size++; // 更新元素数量
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 强制入队操作(覆盖式添加)
|
||||
* \param[in] queue: 队列对象指针
|
||||
* \param[in] data: 待添加数据地址(NULL表示仅移动指针)
|
||||
* \return 1=成功, 0=失败(仅当队列无效时)
|
||||
*
|
||||
* \details 当队列未满时等同于queue_push()。
|
||||
* 当队列已满时覆盖最旧数据(队头数据),
|
||||
* 实现循环缓冲效果。
|
||||
*/
|
||||
int queue_push2(queue queue, void* data)
|
||||
{
|
||||
if (!queue) return 0;
|
||||
if (queue->size < queue->capacity) return queue_push(queue, data); // 队列未满时调用标准入队
|
||||
|
||||
// 队列已满时覆盖队头数据(实现循环覆盖)
|
||||
if (data) assign(at(queue->tail), data);
|
||||
queue->tail = (queue->tail + 1) % queue->capacity;
|
||||
queue->head = (queue->head + 1) % queue->capacity; // 头指针后移(覆盖最旧数据)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 出队操作(队头移除)
|
||||
* \param[in] queue: 队列对象指针
|
||||
* \param[out] data: 数据接收地址(NULL表示丢弃数据)
|
||||
* \return 1=成功, 0=失败(队列无效或为空)
|
||||
*
|
||||
* \details 从队列头部移除元素。如果data不为NULL,
|
||||
* 将移除的元素复制到指定地址。
|
||||
* 更新头指针和队列大小。
|
||||
*/
|
||||
int queue_pop(queue queue, void* data)
|
||||
{
|
||||
if (!queue) return 0;
|
||||
if (queue->size == 0) return 0; // 队列为空
|
||||
if (data) assign(data, at(queue->head)); // 复制队头数据到输出
|
||||
queue->head = (queue->head + 1) % queue->capacity; // 更新头指针(循环)
|
||||
queue->size--; // 更新元素数量
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 指定位置插入元素
|
||||
* \param[in] queue: 队列对象指针
|
||||
* \param[in] index: 插入位置索引(0=队头, size=队尾)
|
||||
* \param[in] data: 待插入数据地址(NULL表示仅空出位置)
|
||||
* \return 1=成功, 0=失败(索引越界或队列已满)
|
||||
*
|
||||
* \details 在指定位置插入新元素,后续元素后移。
|
||||
* 自动选择最优移动方向(前移或后移元素)。
|
||||
* 时间复杂度O(min(index, size-index))。
|
||||
*/
|
||||
int queue_insert(queue queue, int index, void* data)
|
||||
{
|
||||
if (!queue) return 0;
|
||||
if (index < 0 || index > queue->size) return 0; // 索引越界检查
|
||||
if (queue->size == queue->capacity) return 0; // 队列已满
|
||||
|
||||
// 根据插入位置选择最优移动方向
|
||||
if (index <= queue->size / 2) {
|
||||
// 向前移动前半部分元素
|
||||
move_forward(queue, 0, index);
|
||||
queue->head = (queue->head + queue->capacity - 1) % queue->capacity; // 头指针前移
|
||||
} else {
|
||||
// 向后移动后半部分元素
|
||||
move_backward(queue, index, queue->size - index);
|
||||
queue->tail = (queue->tail + 1) % queue->capacity; // 尾指针后移
|
||||
}
|
||||
|
||||
// 在空出的位置插入数据
|
||||
if (data) assign(at((queue->head + index) % (queue->capacity)), data);
|
||||
queue->size++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 指定位置删除元素
|
||||
* \param[in] queue: 队列对象指针
|
||||
* \param[in] index: 删除位置索引(0=队头, size-1=队尾)
|
||||
* \param[out] data: 数据接收地址(NULL表示丢弃数据)
|
||||
* \return 1=成功, 0=失败(索引越界或队列为空)
|
||||
*
|
||||
* \details 删除指定位置元素,后续元素前移。
|
||||
* 自动选择最优移动方向。
|
||||
* 时间复杂度O(min(index, size-index))。
|
||||
*/
|
||||
int queue_erase(queue queue, int index, void* data)
|
||||
{
|
||||
if (!queue) return 0;
|
||||
if (index < 0 || index >= queue->size) return 0; // 索引越界检查
|
||||
if (queue->size == 0) return 0; // 队列为空
|
||||
|
||||
// 保存被删除元素(如果需要)
|
||||
if (data) assign(data, at((queue->head + index) % (queue->capacity)));
|
||||
|
||||
// 根据删除位置选择最优移动方向
|
||||
if (index <= queue->size / 2) {
|
||||
// 向后移动前半部分元素
|
||||
move_backward(queue, 0, index);
|
||||
queue->head = (queue->head + 1) % queue->capacity; // 头指针后移
|
||||
} else {
|
||||
// 向前移动后半部分元素
|
||||
move_forward(queue, index + 1, queue->size - index - 1);
|
||||
queue->tail = (queue->tail + queue->capacity - 1) % queue->capacity; // 尾指针前移
|
||||
}
|
||||
|
||||
queue->size--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 清空队列
|
||||
* \param[in] queue: 队列对象指针
|
||||
*
|
||||
* \details 重置队列状态(头尾指针归零,大小归零)。
|
||||
* 不释放存储内存,保持队列容量不变。
|
||||
*/
|
||||
void queue_clear(queue queue)
|
||||
{
|
||||
if (!queue) return;
|
||||
queue->tail = 0;
|
||||
queue->head = 0;
|
||||
queue->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 获取元素地址
|
||||
* \param[in] queue: 队列对象指针
|
||||
* \param[in] index: 元素索引(0=队头, size-1=队尾)
|
||||
* \return 元素地址(失败返回NULL)
|
||||
*
|
||||
* \details 获取队列中指定位置元素的直接指针。
|
||||
* 可用于直接修改元素值(无需复制)。
|
||||
* \warning 返回的指针在队列结构修改后可能失效。
|
||||
*/
|
||||
void* queue_data(queue queue, int index)
|
||||
{
|
||||
if (!queue) return 0;
|
||||
if (index < 0 || index >= queue->size) return 0; // 索引越界检查
|
||||
return (void*)at((queue->head + index) % (queue->capacity));
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#ifndef _ALGO_QUEUE_H_
|
||||
#define _ALGO_QUEUE_H_
|
||||
|
||||
/* 队列类型定义 */
|
||||
typedef struct QUEUE
|
||||
{
|
||||
void* base; /* 数据存储区的基地址 */
|
||||
int dsize; /* 每个数据元素的大小(字节) */
|
||||
int capacity; /* 队列的总容量(最大元素数量) */
|
||||
int size; /* 当前队列中的元素数量 */
|
||||
int head; /* 队头索引(指向第一个元素) */
|
||||
int tail; /* 队尾索引(指向下一个插入位置) */
|
||||
} *queue; // 定义queue为指向该结构的指针类型
|
||||
|
||||
/**
|
||||
* \brief 创建并初始化一个队列
|
||||
* \param[in] type: 队列元素的数据类型
|
||||
* \param[in] capacity: 队列容量
|
||||
* \return 初始化完成的队列对象
|
||||
*
|
||||
* \note 使用复合字面量在栈上创建队列对象
|
||||
* \example queue(int, 10) 创建容量为10的整型队列
|
||||
*/
|
||||
#define queue(type, capacity) (&(struct QUEUE){(type[capacity]){0},sizeof(type),capacity,0,0,0})
|
||||
|
||||
// 函数声明
|
||||
int queue_push(queue queue, void* data);
|
||||
int queue_push2(queue queue, void* data);
|
||||
int queue_pop(queue queue, void* data);
|
||||
int queue_insert(queue queue, int index, void* data);
|
||||
int queue_erase(queue queue, int index, void* data);
|
||||
void queue_clear(queue queue);
|
||||
void* queue_data(queue queue, int index);
|
||||
|
||||
/**
|
||||
* \brief 访问队列指定位置的元素
|
||||
* \param[in] queue: 队列对象
|
||||
* \param[in] type: 元素数据类型
|
||||
* \param[in] i: 元素位置索引(0-based)
|
||||
* \return 指定元素的左值引用
|
||||
*
|
||||
* \example queue_at(q, int, 0) = 42; // 设置队首元素
|
||||
*/
|
||||
#define queue_at(queue, type, i) (*(type *)queue_data((queue),(i)))
|
||||
|
||||
/**
|
||||
* \brief 在队头插入元素
|
||||
* \param[in] queue: 队列对象
|
||||
* \param[in] data: 待插入数据地址(NULL表示不赋值)
|
||||
* \return 操作成功状态(1成功/0失败)
|
||||
*/
|
||||
#define queue_push_front(queue, data) queue_insert((queue), 0, data)
|
||||
|
||||
/**
|
||||
* \brief 在队尾插入元素
|
||||
* \param[in] queue: 队列对象
|
||||
* \param[in] data: 待插入数据地址(NULL表示不赋值)
|
||||
* \return 操作成功状态(1成功/0失败)
|
||||
*/
|
||||
#define queue_push_back(queue, data) queue_push2((queue), data)
|
||||
|
||||
/**
|
||||
* \brief 从队头弹出元素
|
||||
* \param[in] queue: 队列对象
|
||||
* \param[out] data: 接收弹出数据的地址(NULL表示不保存)
|
||||
* \return 操作成功状态(1成功/0失败)
|
||||
*/
|
||||
#define queue_pop_front(queue, data) queue_pop((queue), data)
|
||||
|
||||
/**
|
||||
* \brief 从队尾弹出元素
|
||||
* \param[in] queue: 队列对象
|
||||
* \param[out] data: 接收弹出数据的地址(NULL表示不保存)
|
||||
* \return 操作成功状态(1成功/0失败)
|
||||
*/
|
||||
#define queue_pop_back(queue, data) queue_erase((queue), (queue)->size - 1, data)
|
||||
|
||||
/**
|
||||
* \brief 获取队列当前元素数量
|
||||
* \param[in] queue: 队列对象
|
||||
* \return 队列中的元素数量
|
||||
*/
|
||||
#define queue_size(queue) ((queue)->size)
|
||||
|
||||
/**
|
||||
* \brief 获取队列总容量
|
||||
* \param[in] queue: 队列对象
|
||||
* \return 队列的最大容量
|
||||
*/
|
||||
#define queue_capacity(queue) ((queue)->capacity)
|
||||
|
||||
/**
|
||||
* \brief 检查队列是否为空
|
||||
* \param[in] queue: 队列对象
|
||||
* \return 0表示非空,非0表示空
|
||||
*/
|
||||
#define queue_empty(queue) ((queue)->size == 0)
|
||||
|
||||
/**
|
||||
* \brief 检查队列是否已满
|
||||
* \param[in] queue: 队列对象
|
||||
* \return 0表示未满,非0表示已满
|
||||
*/
|
||||
#define queue_full(queue) ((queue)->size == (queue)->capacity)
|
||||
|
||||
/**
|
||||
* \brief 创建字面量的地址包装
|
||||
* \param[in] type: 数据类型(如int/float等)
|
||||
* \param[in] value: 字面量值
|
||||
* \return 包含该值的临时数组地址
|
||||
*
|
||||
* \note 用于将字面量转换为指针参数
|
||||
* \example queue_push(q, literal(int, 42));
|
||||
*/
|
||||
#ifndef literal
|
||||
#define literal(type, value) ((type[1]){value})
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user