1.队列的定义
队列是一种特殊的线性表,它遵循先进先出(FIFO)的原则。在队列中,只允许在表的一端进行插入操作(队尾),而在另一端进行删除操作(队头)。这种数据结构确保了最先进入队列的元素总是最先离开队列。队列中没有元素时,被称为空队列。队列的组织和实施训练通常由队列条令予以规定,用于规范部队、分队队列及其在各种条件下的运动队形和动作。
出队的是队头,入队的为队尾
2.实现队列
对于队列,我们知道是一种线性表,我们可以使用单链表、双向链表或者数组都可以实现,这里我们首先介绍使用单链表实现的。
对于单链表实现队列,我们知道队列有队头和队尾,所以设置两个指针*phead 和*ptail表示头尾,但是如何找到头和尾需要讨论,如果只是创建一个单链表,那么索引头尾就十分繁琐,所以我们可以设计两个链表,一个存储数据,一个索引头尾,这样就很方便的实现了队列。
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType val;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
解释:创建一个单链表 QueueNode 用来存储队列元素,再创建一个单链表 Queue 索引队头和队尾,插入数据时 QueueNode 使用动态内存申请开辟空间节点 newnode, 尾节点 *ptail 指向新开辟的节点,即索引队尾,队头保持不变,从而实现索引头尾的功能。
3.队列的相关操作
3.1 初始化和销毁
初始化:断言传入指针不为NULL,将起索引作用的链表头尾均置为NULL,链表长度初始化为0。
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
销毁:创建一个cur指针保存头结点,依次释放,最后将整个链表初始化。
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
3.2 插入和删除
插入:队列只有队尾插入,所以直接在QueueNode单链表上动态内存开辟一个newnode新节点,然后让单链表Queue索引头尾,修改Queue中的数据。
// 队尾插入
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->next = NULL;
newnode->val = x;
if (pq->ptail == NULL)
{
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
删除: 首先判断删除的链表是否为NULL,不为NULL则可以删除,所以创建一个新的next 保存待删除节点,释放节点,置为NULL,当然若只有一个节点即*phead就是*ptail,将他们置为NULL即可。
// 队头删除
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->size != 0);
/*QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
if (pq->phead == NULL)
pq->ptail = NULL;*/
// 一个节点
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else // 多个节点
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
3.3 取出队头或队尾的数据
取出队头:这时两个单链表的作用就体现出来了,取队头直接取phead->val的元素即可。
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
取出队尾:直接返回尾节点ptail->val的数据即可。
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}
3.4 判空与计算链表长度
计算链表长度:直接返回Queue中的size即可
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
判空: 判断链表长度是否为0,是则为空,反之不为空。
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}