前言:上篇博客我们学习了栈的相关知识,掌握了栈的结构与特性,这篇博客将带着大家学习队列的相关知识,希望大家继续坚持下去🌹🌹🌹
概念:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的特点
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

队列既可以用数组来实现也可以用链表来实现,但是用数组进行插入操作的时间复杂度为O(N),虽然链表的插入时间复杂度也为O(N),但是我们可以定义个尾节点来方便我们插入操作

队列结构:
typedef int QDataType;
//定义节点结构
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
//定义队列结构
typedef struct Queue
{
QueueNode* phead;//队头
QueueNode* ptail;//队尾
//int size;//队列中有效数据个数
}Queue;因为我们定义了尾节点,所以入队出队操作会很简单
//入队列--队尾
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
//创建值为x的节点
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
//队列为空
if (pq->phead == NULL)
{
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = pq->ptail->next;
}
}入队列首先还是要创建一个节点结构,判断队列是否为空,若为空,直接让头节点和尾节点都指向新节点,若不为空,则新节点的尾部->next指向新节点,再让尾节点走到新节点的位置

在实现出队之前,我们首先要判断队列是否为空,队列不为空我们才可以进行出队
//队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->phead == NULL;
}//出队列--对头
void QueuePop(Queue* pq)
{
assert(!QueueEmpty(pq));
//如果队列只有一个节点
if (pq->phead == pq->ptail)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QueueNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
}当队列中只有一个节点时,直接free,然后置为NULL,如果有多个,先定义个next节点指针指向头节点的下一个节点,free头节点,再让头节点走到next位置就可以了

//取队头数据
QDataType QueueFront(Queue* pq)
{
assert(!QueueEmpty(pq));
return pq->phead->data;
}队头就是phead,直接返回就可以
//取队尾数据
QDataType QueueBack(Queue* pq)
{
assert(!QueueEmpty(pq));
return pq->ptail->data;
}队尾就是ptail,直接返回就可以
test.c:
#include"Queue.h"
void test1()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
printf("队首元素:%d\n",QueueHead(&q));
printf("队尾元素:%d\n",QueueTail(&q));
}
int main()
{
test1();
}测试结果:

//队列有效元素个数
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QueueNode* pcur = pq->phead;
while (pcur)
{
size++;
pcur = pcur->next;
}
return size;
//return pq->size;
}这里涉及到了循环,时间复杂度为O(N),如果这里在队列定义了一个size,就可以直接返回pq->size
//销毁
void QueueDesTroy(Queue* pq)
{
assert(pq);
QueueNode* pcur = pq->phead;
while (pcur)
{
QueueNode* next = pcur->next;
free(pcur);
pcur = next;
}
pq->phead = pq->ptail = NULL;
}遍历队列,每次销毁前存下下一个节点,销毁当前节点后来到下一个节点的位置,最后遍历结束后把pq->phead和pq->ptail都置为空

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
//定义节点结构
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
//定义队列结构
typedef struct Queue
{
QueueNode* phead;//队头
QueueNode* ptail;//队尾
//int size;//队列中有效数据个数
}Queue;
//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDesTroy(Queue* pq);
//入队列--队尾
void QueuePush(Queue* pq, QDataType x);
//队列是否为空
bool QueueEmpty(Queue* pq);
//出队列--对头
void QueuePop(Queue* pq);
//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);
//队列有效元素个数
int QueueSize(Queue* pq);#include"Queue.h"
//初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
}
//入队列--队尾
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
//创建值为x的节点
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
//队列为空
if (pq->phead == NULL)
{
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = pq->ptail->next;
}
}
//队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->phead == NULL;
}
//出队列--对头
void QueuePop(Queue* pq)
{
assert(!QueueEmpty(pq));
//如果队列只有一个节点
if (pq->phead == pq->ptail)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QueueNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
}
//取队头数据
QDataType QueueFront(Queue* pq)
{
assert(!QueueEmpty(pq));
return pq->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{
assert(!QueueEmpty(pq));
return pq->ptail->data;
}
//队列有效元素个数
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QueueNode* pcur = pq->phead;
while (pcur)
{
size++;
pcur = pcur->next;
}
return size;
//return pq->size;
}
//销毁
void QueueDesTroy(Queue* pq)
{
assert(pq);
QueueNode* pcur = pq->phead;
while (pcur)
{
QueueNode* next = pcur->next;
free(pcur);
pcur = next;
}
pq->phead = pq->ptail = NULL;
}#include"Queue.h"
void test01()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);//1 2 3 4
/*QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);*/
printf("队头元素:%d\n", QueueFront(&q));
printf("队尾元素:%d\n", QueueBack(&q));
printf("size:%d\n", QueueSize(&q));
}
int main()
{
test01();
return 0;
}
往期回顾:
总结:这篇博客带着大家实现了队列的相关接口,那么接下来我还会带着大家继续学习二叉树、堆等相关出街数据结构,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持🌹🌹🌹