前言
在上一章讲了栈的代码实现,而还有一种和栈恰好相反的结构,叫做队列。
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:
进行插入操作的一端称为队尾
出队列:
进行删除操作的一端称为队头
如图所示:
因为队列特有的结构,我们可以用数组和链表来实现,但由于队列需要在头进行操作,数组的效率就不会很高,而链表的结构就相对更优一些,所以我们使用链表来实现队列。
代码实现
队列的代码实现如下:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef int QDatatype;
//用链表的结点来作为队列里的数据结点
typedef struct QueueNode
{
QDatatype a;
struct QueueNode* next;
}QNode;
//由于队列需要在头尾进行操作,所以需要头和尾两个指针,我们将其封装在一起,使代码更加简洁
typedef struct Queue
{
QNode* head;
QNode* tail;
//size用来计算当前队列内元素个数
int size;
}Queue;
//队列的初始化和销毁
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
//入队和出队
void QueuePush(Queue* pq, QDatatype x);
void QueuePop(Queue* pq);
//队列元素个数
int QueueSize(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
//队尾节点和队头节点
QDatatype QueueFront(Queue* pq);
QDatatype QueueBack(Queue* pq);
#include "Queue.h"
//队列的初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
//队列的销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur =next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
//入队
void QueuePush(Queue* pq, QDatatype x)
{
assert(pq);
QNode* node = (QNode*)malloc(sizeof(QNode));
if (node == NULL)
{
perror("malloc fail");
return;
}
node->a = x;
node->next = NULL;
//如果头尾都是空,则为第一次入队
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = node;
pq->tail = node;
}
//否则直接修改尾指针即可
else
{
pq->tail->next = node;
pq->tail = node;
}
//每次入队,size都+1
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
//队列不为空才能进行删除
assert(pq->head!=NULL);
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
//如果删完没有元素了,那么头尾指针都应指向空
if (pq->head == NULL)
{
pq->tail = NULL;
}
pq->size--;
}
//队列元素个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
//队头结点
QDatatype QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->a;
}
//队尾结点
QDatatype QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->a;
}
总结
整体来说,队列的实现和栈有着很多相同之处,所以代码有很多一样的操作,合理利用队列和栈结构特性,就可以解决很多问题。
以上就是本人对队列的一些理解,不足之处请大佬批评指正,共同进步🌹