Hello everybody!今天给大家讲讲队列的相关知识。队列,属于一种数据结构。从字面意思上理解,就像是排队一样,在食堂中,先排队的人自然就先买到饭。队列也是如此,先入队列的数据自然就先出队列。希望大家可以通过这篇文章解决自己心中的疑惑!那废话不多说,让我们开始叭!
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列遵循先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
队列可以以数组和链表的结构实现,使用链表的结构实现更优,因为如果使用数组的结构,出队列是需要移动数据,时间复杂度是O(n),效率比较低。
由于实现队列需要较长的代码,因此我们要像公司中做大型项目一样创建一个头文件:Queue.h和两个源文件:Queue.c Test.c。
头文件中需要包含所需要的库文件,接口的声明,队列的声明。总之就是要我们清晰的看到队列的结构和功能。
而源文件Queue.c需要实现在头文件中声明的接口。
源文件Test.c用于测试队列的功能是否正常。
当然源文件需要包含头文件,这样才能把它们关联起来。
创建三个文件使得代码逻辑更加清晰,有利于后期代码的维护。
这是队列的结构,结构体QNode是队列的链式结构,它可以存放当前结点的值和下一个结点的地址。但是当队列为空,插入第一个数据时,需要改变头指针。因此需要传递二级指针,这样显然是有些麻烦的。所以我们再创建一个结构体Queue,用于存放队列的头指针和尾指针,更方便入队和出队。size用来记录队列中的元素个数。
以上是队列主要功能的接口,下面我们来逐个实现它们。
目前为止,我们已经实现了初始化和入队两个接口。下面测试一下它们的功能。
通过调试,我们可以看到:初始化后,在队尾成功插入1和2。目前队列中有两个数值,接口功能正常。
下面我们来实现一下其他的接口:
这是队列剩下的接口,咱们也来测试一下。
从测试结果来看:各个接口功能正常,销毁队列后,头指针和尾指针都被置为空指针,队列大小size为0。符合要求。
为了方便大家更好的学习,队列的代码我也给出来!
#pragma once
#include
#include
#include
#include
typedef int QDataType;
typedef struct QueueNode {
QDataType val;
struct QueueNode* next;
}QNode;
typedef struct Queue {
QNode* phead;
QNode* ptail;
int size;
}Queue;
void QueueInit(Queue* pq);//初始化
void QueuePush(Queue* pq, QDataType x);//入队
void QueuePop(Queue* pq);//出队
void QueueDestroy(Queue* pq);//销毁
QDataType QueueFront(Queue* pq);//返回队头的值
QDataType QueueBack(Queue* pq);//返回队尾的值
bool QueueEmpty(Queue* pq);//判断队列是否为空
int QueueSize(Queue* pq);//返回队列的数据个数
#include "Queue.h"
void QueueInit(Queue* pq) {
assert(pq);//检验pq是否为空指针
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x) {
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));//动态开辟一个新结点
if (newnode == NULL) {//若开辟失败,终止程序
perror("malloc fail");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
if (pq->phead == NULL) {//如果队列中没有结点,则将新结点赋值给头指针和尾指针
pq->phead = pq->ptail = newnode;
}
else {
pq->ptail->next = newnode;//有结点的话,将新结点赋值给尾指针
pq->ptail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq) {
assert(pq);
assert(pq->phead);//队列不能为空
QNode* next = pq->phead->next;//记录头结点的下一个结点
free(pq->phead);
pq->phead = next;
if (pq->phead == NULL) {//当phead为NULL时,ptail没有变化。但ptail指向的空间已经还给操作系统,此时ptail就是野指针,必须处理掉!
pq->ptail = NULL;
}
pq->size--;
}
QDataType QueueFront(Queue* pq) {
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
QDataType QueueBack(Queue* pq) {
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}
bool QueueEmpty(Queue* pq) {
assert(pq);
return pq->phead == NULL;
}
int QueueSize(Queue* pq) {
assert(pq);
return pq->size;
}
void QueueDestroy(Queue* pq) {
assert(pq);
while (pq->phead) {
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
#include "Queue.h"
int main() {
Queue pq;
QueueInit(&pq);
QueuePush(&pq, 1);
QueuePush(&pq, 2);
QueuePush(&pq, 3);
QueuePush(&pq, 4);
printf("%d\n", QueueBack(&pq));
printf("%d\n", QueueSize(&pq));
while (!QueueEmpty(&pq)) {
printf("%d", QueueFront(&pq));
QueuePop(&pq);
}
QueueDestroy(&pq);
return 0;
}
好啦,关于队列的讨论就到这里叭。不知道大家有没有收获呢?如果有疑问,可以发在评论区。
最后,希望宝子们每天都有所进步,成为自己想成为的人,做自己想做的事!\(0^◇^0)/