#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)); }