前言
介绍
🍃数据结构专区:数据结构
参考
该部分知识参考于《数据结构(C语言版 第2版)》24~28页
🌈每一个清晨,都是世界对你说的最温柔的早安:ૢ(≧▽≦)و✨
目录
[2.1 宏定义](#2.1 宏定义)
[2.2 数组队列的结构体定义](#2.2 数组队列的结构体定义)
[2.3 队列的初始化](#2.3 队列的初始化)
[2.4 销毁队列](#2.4 销毁队列)
[2.5 求队列长度](#2.5 求队列长度)
[2.6 入队](#2.6 入队)
[2.7 出队](#2.7 出队)
[2.8 获取队头元素](#2.8 获取队头元素)
[2.9 遍历打印](#2.9 遍历打印)
[2.10 整体代码(含测试)](#2.10 整体代码(含测试))
[3.1 宏定义](#3.1 宏定义)
[3.2 链表队列的结构体定义](#3.2 链表队列的结构体定义)
[3.3 队列的初始化](#3.3 队列的初始化)
[3.4 销毁队列](#3.4 销毁队列)
[3.5 求队列中元素个数](#3.5 求队列中元素个数)
[3.6 入队](#3.6 入队)
[3.7 出队](#3.7 出队)
[3.8 获取队头元素](#3.8 获取队头元素)
[3.9 输出队列元素](#3.9 输出队列元素)
[3.10 整体代码(含测试)](#3.10 整体代码(含测试))
1、队列的基本概念
队列(Queue)是一种特殊的线性表 ,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。这种操作原则使得队列具有**先进先出(FIFO, First In First Out)**的特性。
- 基于数组的队列:在这种实现中,队列被限制在一个固定大小的数组中。需要维护两个指针,一个指向队首(front),另一个指向队尾(rear)。当进行入队操作时,如果rear指针指向数组的最后一个位置,且队列未满,可能需要将队列中的元素整体向前移动(或称为"循环"数组),以为新元素腾出空间。
- 基于链表的队列:在这种实现中,队列由节点组成的链表来表示。每个节点包含数据部分和指向下一个节点的指针。队首和队尾分别由两个指针(head和tail)来维护。这种实现方式更加灵活,因为它不需要预先分配固定大小的存储空间,并且可以在常数时间内完成入队和出队操作。
2、基于数组的队列
2.1 宏定义
cpp
#include<iostream>
using namespace std;
//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;
2.2 数组队列的结构体定义
cpp
#define MAXQSIZE 100 //队列可能达到的最大长度
typedef int QElemType;
typedef struct
{
QElemType* base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
//队空的条件:Q.front == Q.rear
//队满的条件:(Q.rear + 1) % MAXQSIZE == Q.front
2.3 队列的初始化
cpp
//队列初始化
Status InitQueue(SqQueue& Q)
{
//构造一个空队列Q
Q.base = new QElemType[MAXQSIZE]; //为队列分配一个最大容量为MAXQSIZE的数组空间
//Q.base = (int*)malloc(MAXQSIZE * sizeof(int));
if (!Q.base)
exit(OVERFLOW); //如果开辟失败就退出程序
Q.front = Q.rear = 0; //头尾指针指向0,表示队列为空
return OK;
}
2.4 销毁队列
cpp
// 销毁队列
Status DestroyQueue(SqQueue& Q)
{
if (Q.base) {
delete[] Q.base;
Q.base = NULL;
Q.front = Q.rear = 0;
}
return OK;
}
2.5 求队列长度
cpp
//求队列长度
int QueueLength(SqQueue Q)
{
//返回队列元素个数
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
2.6 入队
cpp
//入队
Status EnQueue(SqQueue& Q, QElemType e)
{
//插入元素e为Q的新的队尾元素
if ((Q.rear + 1) % MAXQSIZE == Q.front)
return ERROR; //若尾指针在循环意义上加1后等于头指针,表明队满
Q.base[Q.rear] = e; //新元素插入队尾
Q.rear = (Q.rear + 1) % MAXQSIZE; //队尾指针加1
return OK;
}
2.7 出队
cpp
//出队
Status DeQueue(SqQueue& Q, QElemType& e)
{
//删除队头元素,用e返回其值
if (Q.front == Q.rear)
return ERROR; //队空
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXQSIZE;
return OK;
}
2.8 获取队头元素
cpp
//取队头元素
QElemType GetHead(SqQueue Q)
{
//返回队头元素,不改变头指针
if (Q.front != Q.rear) //队列非空
return Q.base[Q.front];
}
2.9 遍历打印
cpp
//输出队列元素
void PrintQueue(SqQueue& Q)
{
printf("(front) ");
int i;
for (i = Q.front; i != Q.rear; i++)
{
printf("%d ", Q.base[i]);
}
printf("(rear)\n");
}
2.10 整体代码(含测试)
cpp
#include<iostream>
using namespace std;
//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;
#define MAXQSIZE 100 //队列可能达到的最大长度
typedef int QElemType;
typedef struct
{
QElemType* base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
//队空的条件:Q.front == Q.rear
//队满的条件:(Q.rear + 1) % MAXQSIZE == Q.front
//队列初始化
Status InitQueue(SqQueue& Q)
{
//构造一个空队列Q
Q.base = new QElemType[MAXQSIZE]; //为队列分配一个最大容量为MAXQSIZE的数组空间
//Q.base = (int*)malloc(MAXQSIZE * sizeof(int));
if (!Q.base)
exit(OVERFLOW); //如果开辟失败就退出程序
Q.front = Q.rear = 0; //头尾指针指向0,表示队列为空
return OK;
}
// 销毁队列
Status DestroyQueue(SqQueue& Q)
{
if (Q.base) {
delete[] Q.base;
Q.base = NULL;
Q.front = Q.rear = 0;
}
return OK;
}
//求队列长度
int QueueLength(SqQueue Q)
{
//返回队列元素个数
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
//入队
Status EnQueue(SqQueue& Q, QElemType e)
{
//插入元素e为Q的新的队尾元素
if ((Q.rear + 1) % MAXQSIZE == Q.front)
return ERROR; //若尾指针在循环意义上加1后等于头指针,表明队满
Q.base[Q.rear] = e; //新元素插入队尾
Q.rear = (Q.rear + 1) % MAXQSIZE; //队尾指针加1
return OK;
}
//出队
Status DeQueue(SqQueue& Q, QElemType& e)
{
//删除队头元素,用e返回其值
if (Q.front == Q.rear)
return ERROR; //队空
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXQSIZE;
return OK;
}
//取队头元素
QElemType GetHead(SqQueue Q)
{
//返回队头元素,不改变头指针
if (Q.front != Q.rear) //队列非空
return Q.base[Q.front];
}
//输出队列元素
void PrintQueue(SqQueue& Q)
{
printf("(front) ");
int i;
for (i = Q.front; i != Q.rear; i++)
{
printf("%d ", Q.base[i]);
}
printf("(rear)\n");
}
int main()
{
SqQueue Q;
QElemType e;
cout << "初始化队列..." << endl;
if (InitQueue(Q) == OK)
cout << "队列初始化成功!" << endl;
else
cout << "队列初始化失败!" << endl;
cout << "\n测试入队操作:" << endl;
for (int i = 1; i <= 5; i++)
{
if (EnQueue(Q, i) == OK)
cout << i << " 入队成功" << endl;
else
cout << i << " 入队失败" << endl;
}
cout << "\n当前队列:" << endl;
PrintQueue(Q);
cout << "\n队列长度:" << QueueLength(Q) << endl;
cout << "\n测试出队操作:" << endl;
for (int i = 0; i < 3; i++)
{
if (DeQueue(Q, e) == OK)
cout << e << " 出队成功" << endl;
else
cout << "出队失败,队列可能为空" << endl;
}
cout << "\n当前队列:" << endl;
PrintQueue(Q);
cout << "\n队列长度:" << QueueLength(Q) << endl;
cout << "\n队头元素:" << GetHead(Q) << endl;
cout << "\n销毁队列..." << endl;
if (DestroyQueue(Q) == OK)
cout << "队列销毁成功!" << endl;
else
cout << "队列销毁失败!" << endl;
return 0;
}
3、基于链表的队列
3.1 宏定义
cpp
//链队列的实现
#include<iostream>
using namespace std;
//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;
3.2 链表队列的结构体定义
cpp
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode* next;
}QNode, *QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
3.3 队列的初始化
cpp
//队列初始化
Status InitQueue(LinkQueue& Q)
{
//构造一个空队列
Q.front = Q.rear = new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点
Q.front->next = NULL; //头结点的指针域置空
return OK;
}
3.4 销毁队列
cpp
//销毁队列
Status DestroyQueue(LinkQueue& Q)
{
while (Q.front)
{
Q.rear = Q.front->next;
delete Q.front;
Q.front = Q.rear;
}
return OK;
}
3.5 求队列中元素个数
cpp
//求队列中元素数量
int QueueLength(LinkQueue Q)
{
int count = 0;
QNode* p = Q.front->next;
while (p)
{
count++;
p = p->next;
}
return count;
}
3.6 入队
cpp
//入队
Status EnQueue(LinkQueue& Q, QElemType e)
{
//插入元素e为Q的新的队尾元素
QNode* p = new QNode;
p->data = e;
p->next = NULL;
Q.rear->next = p; //将新结点插入队尾
Q.rear = p; //修改队尾指针
return OK;
}
3.7 出队
cpp
//出队
Status DeQueue(LinkQueue& Q, QElemType& e)
{
//删除队头元素,用e返回其值
if (Q.front == Q.rear)
return ERROR; //若队列为空,返回ERROR
QNode* p = Q.front->next;
e = p->data; //用e保存头结点数据
Q.front->next = p->next; //修改头结点指针域
if (Q.rear == p)
Q.rear = Q.front; //最后一个元素被删除,队尾指针指向头结点
delete p; //释放原队头元素的空间
return OK;
}
3.8 获取队头元素
cpp
//取队头元素
QElemType GetHead(LinkQueue Q)
{
//返回Q的队头元素,不修改头指针
if (Q.front != Q.rear)
return Q.front->next->data; //返回头元素的值,队头元素不变
}
3.9 输出队列元素
cpp
//输出队列元素
void PrintQueue(LinkQueue Q)
{
//前提队列不为空
printf("(front) ");
if (Q.front != Q.rear)
{
QNode* p = Q.front->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
}
printf("(rear)\n");
}
3.10 整体代码(含测试)
cpp
//链队列的实现
#include<iostream>
using namespace std;
//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode* next;
}QNode, *QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
//队列初始化
Status InitQueue(LinkQueue& Q)
{
//构造一个空队列
Q.front = Q.rear = new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点
Q.front->next = NULL; //头结点的指针域置空
return OK;
}
//销毁队列
Status DestroyQueue(LinkQueue& Q)
{
while (Q.front)
{
Q.rear = Q.front->next;
delete Q.front;
Q.front = Q.rear;
}
return OK;
}
//求队列中元素数量
int QueueLength(LinkQueue Q)
{
int count = 0;
QNode* p = Q.front->next;
while (p)
{
count++;
p = p->next;
}
return count;
}
//入队
Status EnQueue(LinkQueue& Q, QElemType e)
{
//插入元素e为Q的新的队尾元素
QNode* p = new QNode;
p->data = e;
p->next = NULL;
Q.rear->next = p; //将新结点插入队尾
Q.rear = p; //修改队尾指针
return OK;
}
//出队
Status DeQueue(LinkQueue& Q, QElemType& e)
{
//删除队头元素,用e返回其值
if (Q.front == Q.rear)
return ERROR; //若队列为空,返回ERROR
QNode* p = Q.front->next;
e = p->data; //用e保存头结点数据
Q.front->next = p->next; //修改头结点指针域
if (Q.rear == p)
Q.rear = Q.front; //最后一个元素被删除,队尾指针指向头结点
delete p; //释放原队头元素的空间
return OK;
}
//取队头元素
QElemType GetHead(LinkQueue Q)
{
//返回Q的队头元素,不修改头指针
if (Q.front != Q.rear)
return Q.front->next->data; //返回头元素的值,队头元素不变
}
//输出队列元素
void PrintQueue(LinkQueue Q)
{
//前提队列不为空
printf("(front) ");
if (Q.front != Q.rear)
{
QNode* p = Q.front->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
}
printf("(rear)\n");
}
int main()
{
LinkQueue Q;
QElemType e;
cout << "初始化队列..." << endl;
if (InitQueue(Q) == OK)
cout << "队列初始化成功!" << endl;
else
cout << "队列初始化失败!" << endl;
cout << "\n测试入队操作:" << endl;
for (int i = 1; i <= 5; i++)
{
if (EnQueue(Q, i) == OK)
cout << i << " 入队成功" << endl;
else
cout << i << " 入队失败" << endl;
}
cout << "\n当前队列:" << endl;
PrintQueue(Q);
cout << "\n队列长度:" << QueueLength(Q) << endl;
cout << "\n测试出队操作:" << endl;
for (int i = 0; i < 3; i++)
{
if (DeQueue(Q, e) == OK)
cout << e << " 出队成功" << endl;
else
cout << "出队失败,队列可能为空" << endl;
}
cout << "\n当前队列:" << endl;
PrintQueue(Q);
cout << "\n队列长度:" << QueueLength(Q) << endl;
cout << "\n队头元素:" << GetHead(Q) << endl;
cout << "\n销毁队列..." << endl;
if (DestroyQueue(Q) == OK)
cout << "队列销毁成功!" << endl;
else
cout << "队列销毁失败!" << endl;
return 0;
}
结语
到此我们队列的基本操作也就完成了,那么我们对于数据结构中的顺序表、栈、队列的学习已经基本完成,可以进行一些简单的力扣题的书写了,这里并没有太大的难度,需要的是不断去熟悉和练习来完成对这部分知识的掌握!