👉队列的概念及结构👈
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的原则
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
队列的结构在生活中非常地常见,比如排队时的抽号机就是一个典型的队列结构。那队列如何实现呢?我们一起来看一下。
👉队列的实现👈
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些。因为如果使用数组的结构,出队列在数组头上出数据,需要挪动数据,时间复杂度为O(N)
,效率会比较低。
Queue.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> typedef int QDataType; typedef struct QueueNode { QDataType data; struct QueueNode* next; }QNode; typedef struct Queue { QNode* head; // 头指针 QNode* tail; // 尾指针 int size; // 节点的个数 }Queue; void QueueInit(Queue* pq); void QueueDestroy(Queue* pq); void QueuePush(Queue* pq, QDataType x); void QueuePop(Queue* pq); QDataType QueueFront(Queue* pq); QDataType QueueBack(Queue* pq); bool QueueEmpty(Queue* pq); int QueueSize(Queue* pq);
队列要实现的函数接口有:初始化队列、销毁队列、数据入队、数据出队、返回队头的数据、返回队尾的数据、判断队列是否为空以及队列中数据的个数。这些接口实现起来也不是很难,我们一起来看一下。
Queue.c
#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* del = cur; cur = cur->next; free(del); } pq->head = pq->tail = 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); } else { newnode->data = x; newnode->next = NULL; } // 队列中没有节点 if (pq->tail == NULL) { pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } pq->size++; } void QueuePop(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); // 队列中只有一个节点 if (pq->head->next == NULL) { free(pq->head); pq->head = pq->tail = NULL; } else { QNode* del = pq->head; pq->head = pq->head->next; free(del); //del = NULL; } pq->size--; } QDataType QueueFront(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->head->data; } QDataType QueueBack(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->tail->data; } bool QueueEmpty(Queue* pq) { assert(pq); return pq->size == 0; //return pq->head == NULL && pq->tail == NULL; } int QueueSize(Queue* pq) { assert(pq); return pq->size; }
初始化队列
头指针和尾指针都指向空,队列元素个数初始化为0
void QueueInit(Queue* pq) { assert(pq); pq->head = pq->tail = NULL; pq->size = 0; }
销毁队列
利用
while
循环将申请的节点一一释放掉,然后头指针pq->head
和尾指针pq->tail
指向空,栈的数据个数置为 0pq->size = 0
void QueueDestroy(Queue* pq) { assert(pq); QNode* cur = pq->head; while (cur) { QNode* del = cur; cur = cur->next; free(del); } pq->head = pq->tail = NULL; pq->size = 0; }
数据入队
1.申请新的节点newnode newnode->data = x,newnode->next = NULL
2.数据入队:当pq->tail == NULL时,队列中没有节点,那么头指针和尾指针都赋值为newnode pq->head = pq->tail = newnode;当pq->tail != NULL时,队列中有节点,那么尾部链接上新节点newnode,然后newnode成为新的尾结点。
3.队列数据个数加一pq->size++
void QueuePush(Queue* pq, QDataType x) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); if (newnode == NULL) { perror("malloc fail"); exit(-1); } else { newnode->data = x; newnode->next = NULL; } // 队列中没有节点 if (pq->tail == NULL) { pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } pq->size++; }
数据出队
1.判断队列是否为空
2.数据出队:当pq->head->next == NULL时,队列中只有一个节点,释放该节点,头指针和尾指针都指向空;当pq->head->next != NULL时,释放让头指针指向当前节点的下一个节点,释放原来的头节点
3.队列数据个数减一pq->size--
void QueuePop(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); // 队列中只有一个节点 if (pq->head->next == NULL) { free(pq->head); pq->head = pq->tail = NULL; } else { QNode* del = pq->head; pq->head = pq->head->next; free(del); //del = NULL; } pq->size--; }
返回队头数据
先判断队列是否为空,不为空时,返回队头数据。
QDataType QueueFront(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->head->data; }
返回队尾数据
先判断队列是否为空,不为空时,返回队尾数据。
QDataType QueueFront(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->tail->data; }
判断队列是否为空
判断队列是否为空有两种方式:1.判断
pq->size
等不等于 0;2.判断头指针pq->head
和尾指针pq->tail
是否等于空指针NULL
bool QueueEmpty(Queue* pq) { assert(pq); return pq->size == 0; //return pq->head == NULL && pq->tail == NULL; }
队列中数据的个数
直接返回队列数据的个数
pq->size
int QueueSize(Queue* pq) { assert(pq); return pq->size; }
Test.c
以下为测试函数接口的代码,大家可以参考一下。需要注意的是,打印队列中的数据是通过打印队头数据、Pop
掉队头数据的方式来实现的。
#include "Queue.h" void QueueTest() { Queue q; QueueInit(&q); QueuePush(&q, 1); QueuePush(&q, 2); QueuePush(&q, 3); printf("%d ", QueueFront(&q)); QueuePop(&q); printf("%d ", QueueFront(&q)); QueuePop(&q); QueuePush(&q, 4); QueuePush(&q, 5); QueuePush(&q, 6); while (!QueueEmpty(&q)) { printf("%d ", QueueFront(&q)); QueuePop(&q); } printf("\n"); QueueDestroy(&q); } int main() { QueueTest(); return 0; }
👉总结👈
本篇博客主要讲解了队列的实现,最重要的函数接口是数据入队和数据出队。在下一篇博客,本人将给大家带来几道 OJ 题,大家可以期待一下。以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家啦!💖💝❣️