🐨文章目录
🎸0. 前言
- 可能有部分小伙伴在使用电脑时,用鼠标点击应用程序的快捷方式时,怎么点击都没反应,正当你烦躁的时候,突然你先前点击的操作都被执行了。
- 还有就是,我们有时候网购,咨询人工客服,高峰期时页面会显示你前面还有多少人,请耐心等待。
- 其实这两个方面都应用了一种数据结构来实现这种功能,这就是队列。
🎺1. 队列的概念和结构
🎼1.1 概念
队列和栈相反,队列是一种先进先出(First In First Out,简称FIFO)的线性表,它只允许在表的一段进行插入,另一端进行删除。
- 入队:进行插入的一段叫队头。
- 出队:进行删除的一段叫队尾。
🎼1.2 结构
队列因为要涉及到头删和尾插,那么使用链式结构效率会相对高一点。本篇文章的实现方式采用链式队列。
🥁2. 接口声明
队列的只需要入队和出队操作,即头删和尾插,那么我们定义一个头指针(head)和一个尾指针(tail)。但是这里如果定义两个数据的话,我们传参的时候就会非常的麻烦,所以我们用结构封装起来。
tips:
为什么同样是链式结构,为什么单链表不设计尾指针呢?
- 因为单链表还要涉及到尾删和中间位置删除,这样就算定义了尾指针,我们还是需要遍历链表,找到删除位置前一个节点,所以没有太大的必要。
- 而这里只是需要进行尾插操作,那么我们定义一个尾指针会很舒服,尾插的时候不需要遍历链表。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
//初始化
void QueueInit(Queue*pq);
//销毁
void QueueDestroy(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
//入队
void QueuePush(Queue* pq, QDataType data);
//出队
void QueuePop(Queue* pq);
//获取队尾元素
QDataType QueueBack(Queue* pq);
//获取对头元素
QDataType QueueFront(Queue* pq);
//获取有效元素个数
int QueueSize(Queue* pq);
🪗3. 接口实现
🎶3.1 初始化和销毁
//初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
//销毁
void QueueDestroy(Queue* pq)
{
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
🎶3.2 判空
//判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
🎶3.3 入队和出队
//入队
void QueuePush(Queue* pq, QDataType data)
{
//尾插
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = data;
newnode->next = NULL;
if (pq->head == NULL)
{
assert(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* newhead = pq->head->next;
free(pq->head);
pq->head = newhead;
}
pq->size--;
}
🎶3.4 获取对头和队尾元素
//获取队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
//获取对头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
🎶3.5 获取有效元素个数
//获取有效元素个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
🎤4. 接口测试
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include"Queue.h"
void TestQueue1()
{
Queue q;
//初始化测试
QueueInit(&q);
//入队测试
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
QueuePush(&q, 7);
int size = QueueSize(&q);
//获取队尾元素测试
printf("%d\n", QueueBack(&q));
while (size--)
{
//获取队头元素测试
printf("%d ", QueueFront(&q));
//出队测试
QueuePop(&q);
}
//销毁测试
QueueDestroy(&q);
}
int main()
{
TestQueue1();
return 0;
}