文章目录
前言
队列(Queue)是一种受限的线性表,它是一种运算受限的线性表,遵循先进先出(FIFO First In First Out)的原则:
1.队列是一种受限的线性结构
2.它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
生活中队列场景随处可见: 比如在电影院, 商场, 或者厕所排队…
一、队列的顺序存储
采用数组来保存队列的元素,设立一个队首指针 front ,一个队尾指针 rear,分别指向队首和队尾元素。则rear-front 即为存储的元素个数!
1.顺序队列的创建
#define MAX_SIZE 5 //队列的最大容量
typedef int Datatype; //队列中元素类型
typedef struct Queue
{
Datatype queue[MAX_SIZE];
int front; //队头指针
int rear; //队尾指针
}SeqQueue;
2.队列的初始化
void InitQueue(SeqQueue *SQ) //初始化队列
{
if(!SQ)
{
cout<<"内存分配失败!"<<endl;
return ;
}
SQ->front=SQ->rear=0; //初始时,front与rear都指向队头
}
3.队列的判空
int IsEmpty(SeqQueue *SQ) //判断队列是否为空
{
if(!SQ)
return 0;
if(SQ->front==SQ->rear) //此时队列为空
return 1;
return 0;
}
4.队列的判满
int IsFull(SeqQueue *SQ) //判断队列是否满了
{
if(!SQ)
return 0;
if(SQ->rear==MAX_SIZE) //此时队列为满
return 1;
return 0;
}
5.元素入队
队列只能在尾部进行元素入队!
int EnterQueue(SeqQueue *SQ,Datatype data) //元素入队
{
if(!SQ)
return 0;
if(IsFull(SQ))
return 0;
SQ->queue[SQ->rear]=data; //元素入队(入rear指针指向的位置)
SQ->rear++; //rear指针后移一位
return 1;
}
6.元素出队
出队方式有两种,第一种是将队首元素移出队列,后面元素向前移动一位,弊端是会大量移动元素。
int DeleteQueue1(SeqQueue* SQ,Datatype* data) //删除front指向的元素,front指向元素之后的元素向前移1,需要移动大量元素
{
if(!SQ||!data)
return 0;
if(IsEmpty(SQ))
{
cout<<"队列为空!"<<endl;
return 0;
}
*data=SQ->queue[SQ->front];
for(int i=SQ->front+1;i<SQ->rear;i++) //将front指向元素的后面元素向前移一位
SQ->queue[i-1]=SQ->queue[i];
SQ->rear--;
return 1;
}
第二种是将front指针想队尾方向移动一位,达到删除目的,弊端是队列会越来越小
int DeleteQueue2(SeqQueue* SQ,Datatype* data) //直接将front后移,队列会越来越小
{
if(!SQ||!data)
return 0;
if(IsEmpty(SQ))
{
cout<<"队列为空"<<endl;
return 0;
}
*data=SQ->queue[SQ->front];
SQ->front=(SQ->front)+1; //front指针向后移一位即可
return 1;
}
7.获取队首元素
int GetHead(SeqQueue* SQ) //获取队首元素
{
if(!SQ||IsEmpty(SQ))
cout<<"队列为空!"<<endl;
return SQ->queue[SQ->front]; //返回队首元素
}
8.元素打印
void PrintQueue(SeqQueue* SQ) //队列元素打印
{
if(!SQ)
return ;
if(IsEmpty(SQ))
return ;
int i=SQ->front;
while(i<(SQ->rear))
{
cout<<setw(4)<<SQ->queue[i];
i++;
}
}
9.完整源码
#include <stdio.h>
#include <assert.h>
#include <iostream>
#include <iomanip>
#define MAX_SIZE 5
using namespace std;
typedef int Datatype;
typedef struct Queue
{
Datatype queue[MAX_SIZE];
int front; //队头指针
int rear; //队尾指针
}SeqQueue;
void InitQueue(SeqQueue *SQ) //初始化队列
{
if(!SQ)
{
cout<<"内存分配失败!"<<endl;
return ;
}
SQ->front=SQ->rear=0;
}
int IsEmpty(SeqQueue *SQ) //判断队列是否为空
{
if(!SQ)
return 0;
if(SQ->front==SQ->rear)
return 1;
return 0;
}
int IsFull(SeqQueue *SQ) //判断队列是否满了
{
if(!SQ)
return 0;
if(SQ->rear==MAX_SIZE)
return 1;
return 0;
}
int EnterQueue(SeqQueue *SQ,Datatype data)
{
if(!SQ)
return 0;
if(IsFull(SQ))
return 0;
SQ->queue[SQ->rear]=data;
SQ->rear++;
return 1;
}
void PrintQueue(SeqQueue* SQ)
{
if(!SQ)
return ;
if(IsEmpty(SQ))
return ;
int i=SQ->front;
while(i<(SQ->rear))
{
cout<<setw(4)<<SQ->queue[i];
i++;
}
}
int DeleteQueue1(SeqQueue* SQ,Datatype* data) //删除front元素,front后的元素向前移1,需要移动大量元素
{
if(!SQ||!data)
return 0;
if(IsEmpty(SQ)) //之前出错是因为手误写成if(IsFull(SQ))
{
cout<<"队列为空!"<<endl;
return 0;
}
*data=SQ->queue[SQ->front];
for(int i=SQ->front+1;i<SQ->rear;i++)
SQ->queue[i-1]=SQ->queue[i];
SQ->rear--;
return 1;
}
int DeleteQueue2(SeqQueue* SQ,Datatype* data) //直接将front后移,队列会越来越小
{
if(!SQ||!data)
return 0;
if(IsEmpty(SQ)) //之前出错是因为手误写成if(IsFull(SQ))
{
cout<<"队列为空"<<endl;
return 0;
}
*data=SQ->queue[SQ->front];
SQ->front=(SQ->front)+1;
return 1;
}
int GetHead(SeqQueue* SQ) //获取队首元素
{
if(!SQ||IsEmpty(SQ))
cout<<"队列为空!"<<endl;
return SQ->queue[SQ->front];
}
void DestroyQueue(SeqQueue* SQ) //清空队列
{
SQ->front=SQ->rear=0;
}
int main()
{
SeqQueue *SQ = new SeqQueue;
Datatype data = -1;
//初始化队列
InitQueue(SQ);
//入队
for(int i=0; i<7; i++)
{
EnterQueue(SQ, i);
}
PrintQueue(SQ);
cout<<endl;
//出队
if(DeleteQueue1(SQ, &data))
{
cout<<"出队的元素是:"<<data<<endl;
}
else
{
cout<<"出队失败!"<<endl;
}
if(DeleteQueue2(SQ, &data))
{
cout<<"出队的元素是:"<<data<<endl;
}
else
{
cout<<"出队失败!"<<endl;
}
//打印队列中的元素
printf("出队一个元素后,队列中剩下的元素:");
PrintQueue(SQ);
cout<<endl;
return 0;
}
二、队列的链式存储
队列的链式存储结构,其实就是线性表的单链表,只不过它只是尾进头出而已,我们把它简称为链队列。为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端节点。
1.链式队列的创建
#define MAX_SIZE 5
typedef int DataType;
typedef struct _QNode
{
DataType data;
struct _QNode *next;
}QNode;
typedef QNode* QueuePtr;
typedef struct Queue
{
int length; //队列长度
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
2.队列的初始化
void InitQueue(LinkQueue *LQ) //初始化队列
{
if(!LQ)
return ;
LQ->length=0;
LQ->front=LQ->rear=NULL; //头指针与尾指针均置空
}
3.队列的判空与元素入队
int IsEmpty(LinkQueue *LQ) //判断队列是否为空
{
if(!LQ)
return 0;
if(LQ->front==NULL)
return 1;
return 0;
}
int EnterQueue(LinkQueue *LQ,DataType data) //入队
{
if(!LQ)
return 0;
if(IsFull(LQ))
{
cout<<"无法插入元素"<<data<<",队列已满"<<endl;
return 0;
}
QNode *qNode=new QNode;
qNode->data=data;
qNode->next=NULL;
if(IsEmpty(LQ))
{
LQ->front=LQ->rear=qNode;
}
else
{
LQ->rear->next=qNode;
LQ->rear=qNode;
}
LQ->length++;
return 1;
}
4.队列的判满
int IsFull(LinkQueue *LQ) //判断队列是否满
{
if(!LQ)
return 0;
if(LQ->length==MAX_SIZE)
{
return 1;
}
return 0;
}
5.元素出队
int DeleteQueue(LinkQueue *LQ,DataType *data) //元素出队
{
QNode *tmp=NULL;
if(!LQ||IsEmpty(LQ))
{
cout<<"队列为空!"<<endl;
return 0;
}
if(!data)
return 0;
tmp=LQ->front;
LQ->front=tmp->next;
if(!LQ->front)
LQ->rear=NULL;
*data=tmp->data;
LQ->length--;
delete tmp;
return 1;
}
6.获取队首元素
int GetHead(LinkQueue *LQ,DataType *data) //获取队首元素
{
if(!LQ||IsEmpty(LQ))
{
cout<<"队列为空!"<<endl;
return 0;
}
if(!data)
return 0;
*data=LQ->front->data;
return 1;
}
7.元素打印
void PrintQueue(LinkQueue *LQ) //队列元素打印
{
QueuePtr tmp;
if(!LQ)
return ;
if(LQ->front==NULL)
cout<<"队列为空!"<<endl;
tmp=LQ->front;
while(tmp)
{
cout<<setw(4)<<tmp->data;
tmp=tmp->next;
}
cout<<endl;
}
8.完整源码
#include <iostream>
#include <stdio.h>
#include <iomanip>
#define MAX_SIZE 5
using namespace std;
typedef int DataType;
typedef struct _QNode
{
DataType data;
struct _QNode *next;
}QNode;
typedef QNode* QueuePtr;
typedef struct Queue
{
int length; //队列长度
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
void InitQueue(LinkQueue *LQ) //初始化队列
{
if(!LQ)
return ;
LQ->length=0;
LQ->front=LQ->rear=NULL;
}
int IsEmpty(LinkQueue *LQ) //判断队列是否为空
{
if(!LQ)
return 0;
if(LQ->front==NULL)
return 1;
return 0;
}
int IsFull(LinkQueue *LQ) //判断队列是否满
{
if(!LQ)
return 0;
if(LQ->length==MAX_SIZE)
{
return 1;
}
return 0;
}
int EnterQueue(LinkQueue *LQ,DataType data) //入队
{
if(!LQ)
return 0;
if(IsFull(LQ))
{
cout<<"无法插入元素"<<data<<",队列已满"<<endl;
return 0;
}
QNode *qNode=new QNode;
qNode->data=data;
qNode->next=NULL;
if(IsEmpty(LQ))
{
LQ->front=LQ->rear=qNode;
}
else
{
LQ->rear->next=qNode;
LQ->rear=qNode;
}
LQ->length++;
return 1;
}
int DeleteQueue(LinkQueue *LQ,DataType *data)
{
QNode *tmp=NULL;
if(!LQ||IsEmpty(LQ))
{
cout<<"队列为空!"<<endl;
return 0;
}
if(!data)
return 0;
tmp=LQ->front;
LQ->front=tmp->next;
if(!LQ->front)
LQ->rear=NULL;
*data=tmp->data;
LQ->length--;
delete tmp;
return 1;
}
void PrintQueue(LinkQueue *LQ) //队列元素打印
{
QueuePtr tmp;
if(!LQ)
return ;
if(LQ->front==NULL)
cout<<"队列为空!"<<endl;
tmp=LQ->front;
while(tmp)
{
cout<<setw(4)<<tmp->data;
tmp=tmp->next;
}
cout<<endl;
}
int GetHead(LinkQueue *LQ,DataType *data) //获取队首元素
{
if(!LQ||IsEmpty(LQ))
{
cout<<"队列为空!"<<endl;
return 0;
}
if(!data)
return 0;
*data=LQ->front->data;
return 1;
}
void ClearQueue(LinkQueue *LQ) //链队列销毁
{
if(!LQ)
return ;
while(LQ->front)
{
QueuePtr tmp=LQ->front->next;
delete LQ->front;
LQ->front=tmp;
}
LQ->front=LQ->rear=NULL;
LQ->length=0;
}
int getLength(LinkQueue *LQ) //队列长度
{
if(!LQ)
return 0;
return LQ->length;
}
int main()
{
LinkQueue *LQ=new LinkQueue;
DataType data=-1;
InitQueue(LQ); //初始化队列
for(int i=0;i<7;i++) //入队
EnterQueue(LQ,i);
printf("队列中的元素(总共%d个):",getLength(LQ)); //打印队列元素
PrintQueue(LQ);
cout<<endl;
if(DeleteQueue(LQ,&data)) //出队
cout<<"出队元素是:"<<data<<endl;
else
cout<<"出队失败!"<<endl;
printf("队列中的元素(总共%d个):",getLength(LQ)); //打印队列元素
PrintQueue(LQ);
cout<<endl;
ClearQueue(LQ);
cout<<"清空队列!"<<endl;
PrintQueue(LQ);
return 0;
}
总结
以上是对队列的初步讲解,如有误处,还请指正。后续还会介绍一些特殊队列。