文章目录
一、什么是队列
和栈一样,队列是一种操作受限制的线性表,只允许在表的前端(front)进行删除操作,称作出队;在表的后端进行插入操作,称为入队。
队列中的元素遵守先进先出(First in First out)的原则。
入队:将一个元素添加到队列的末尾;
出队:移除队列中的第一个元素。
二、队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
2.1 队列的结构
将元素数据类型重命名,方便修改。
typedef int QDataType;
链式结构,表示队列
typedef struct QListNode
{
struct QListNode* _next;//指向下一个元素
QDataType _data;//储存元素
}QNode;
队列的结构,表示队列整体,用队头和队尾表示整个结构,size表示元素个数。
// 队列的结构
typedef struct Queue
{
QNode* _front;//队头
QNode* _rear;//队尾
int size;
}Queue;
2.2 队列的几个功能
- 初始化队列
- 队尾入队列
- 队头出队列
- 获取队列头部元素
- 获取队列队尾元素
- 获取队列中有效元素个数
- 检测队列是否为空,如果为空返回非零结果,如果非空返回0
- 销毁队列
分别由以下函数来实现:
- void QueueInit(Queue* q);
- void QueuePush(Queue* q, QDataType data);
- void QueuePop(Queue* q);
- QDataType QueueFront(Queue* q);
- QDataType QueueBack(Queue* q);
- int QueueSize(Queue* q);
- int QueueEmpty(Queue* q);
- void QueueDestroy(Queue* q);
2.2.1 初始化队列
此时队列中没有元素,指针置空,大小为0。
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_rear = NULL;
q->size = 0;
}
2.2.2 队列判空
检测队列是否为空,如果为空返回非零结果,如果非空返回0 。
返回size
的值即可。
int QueueEmpty(Queue* q)
{
assert(q);
return q->size == 0 ? 1: 0;
}
2.2.3 队尾入队列
入队操作与链表的尾插类似,申请一个节点,使_rear->next
指向此节点。
特殊情况:当队列为空时,_front
指针和_rear
指针必定为空,此时q->_front = q->_rear = newnode
。
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));//新节点
if (newnode == NULL)//申请失败
{
perror("malloc fail\n");
return;
}
newnode->_data = data;//要存储的元素
newnode->_next = NULL;
if (q->_rear == NULL)//队列为空
{
assert(q->_front == NULL);
q->_front = q->_rear = newnode;
}
else//队列非空
{
q->_rear->_next = newnode;
q->_rear = newnode;
}
q->size++;
}
2.2.4 队头出队列
出队分为三种情况:
- 队列为空:此时可用判空函数。
- 队列中只有一个节点:此时头指针和尾指针都指向这个节点,如果要头删,尾指针也要向后移一位。
- 队列中有多个节点:头指针后移,尾指针不动。
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
//只有一个节点
if (q->_front == q->_rear)
{
q->_rear = q->_rear->_next;
}
//先保存再释放
QNode* next = q->_front->_next;
free(q->_front);
q->_front = next;
q->size--;
}
2.2.5 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
return q->_front->_data;
}
2.2.6 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
return q->_rear->_data;
}
2.2.7 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
return q->size;
}
2.2.8 销毁队列
销毁相当于单链表的销毁,但记得要把头尾指针置空。
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->_front;
while (cur)
{
QNode* next = cur->_next;
free(cur);
cur = next;
}
q->_front = q->_rear = NULL;//头尾置空
q->size = 0;
}
三、代码
3.1 Queue.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int QDataType;
// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
int size;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
3.2 Queue.c
#include "Queue.h"
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_rear = NULL;
q->size = 0;
}
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail\n");
return;
}
newnode->_data = data;
newnode->_next = NULL;
if (q->_rear == NULL)
{
assert(q->_front == NULL);
q->_front = q->_rear = newnode;
}
else
{
q->_rear->_next = newnode;
q->_rear = newnode;
}
q->size++;
}
int QueueEmpty(Queue* q)
{
assert(q);
return q->size == 0 ? 1: 0;
}
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
//只有一个节点
if (q->_front == q->_rear)
{
q->_rear = q->_rear->_next;
}
//先保存再释放
QNode* next = q->_front->_next;
free(q->_front);
q->_front = next;
q->size--;
}
QDataType QueueFront(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
return q->_front->_data;
}
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
return q->_rear->_data;
}
int QueueSize(Queue* q)
{
assert(q);
return q->size;
}
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->_front;
while (cur)
{
QNode* next = cur->_next;
free(cur);
cur = next;
}
q->_front = q->_rear = NULL;//头尾置空
q->size = 0;
}
欢迎指正!