一、队列:
简称队,实质是一种操作受限的线性表,其限制为仅允许在表的一端进行插入,在表的另一端进行删除。可以插入的一端是队尾,可以删除的一端是队首。
操作:
入队、出队。
队列的特点:
先进先出(FIFO),就如火车过隧道
队列的存储结构:
队列按存储结构分为顺序队和链队
二、顺序队:
使用数组模拟,队有两个标记,一个标记队首,一个标记队尾。当队首与队尾相等时,表示队空。
元素入队时,队尾标记后移,队尾位置存入元素,如果是第一个入队的元素,则队首指向该元素所在位置的前一个位置。
元素出队时,队首标记后移,指向刚出队元素的位置,取出队首所指的元素。
#include<stdio.h>
#include<malloc.h>
# define MaxSize 8
//顺序队
typedef struct{
int data[MaxSize]; //8
int front;
int rear;
}SqQueue;
//顺序队列判空
void sqEmpty(SqQueue Sq)
{
if(Sq.front == Sq.rear)
{
printf("队列为空\n");
}
}
//顺序队列入队
void pushQueue(SqQueue &Sq,int data){
if(Sq.rear!=MaxSize-1)//队不满
{
Sq.data[++Sq.rear]=data;
printf("%d入队成功\n",data);
}
else
{
printf("%d入队失败\n",data);
}
}
//顺序队列出队
void popQueue(SqQueue &Sq)
{
if(Sq.rear==Sq.front)
{
printf("队空,元素出队失败\n");
}
else
{
printf("%d出队成功\n",Sq.data[++Sq.front]);//front++是先赋值,再运算,队首元素出队后,需要后移到下一个元素位置。
}
}
void initSqQueue()
{
SqQueue Sq;
Sq.front=Sq.rear=-1;//初始化队首队尾指针为-1;
sqEmpty(Sq);
int elem[5]={5,4,6,4,2};//设置初始化队列元素
for(int i=0;i<5;i++)
pushQueue(Sq,elem[i]);//入队
for(int i=0;i<5;i++)
popQueue(Sq);//出队
}
int main()
{
initSqQueue();//顺序队列
}
缺点:
当元素入队后,所有元素出队后,front==rear,队列为空,但是front和rear一直在向数组的后面位置移动,会造成前面空间的浪费,和假溢出的现象(front==rear==MaxSize-1)。于是就有循环队列。
三、循环队列:
把队列弄成一个环,让front和rear都绕着环走,循环队列是改进的顺序队列。
让front标记执行语句 front=(front+1)%MaxSize,若front初值为0,在一个无限循环中,则front取值为0,1,2,3,4,... ,MaxSize-1。即以0 ~ MaxSize-1的无限循环数。rear也是如此。
但是,该循环队列必须留出一个空白空间,因为如果没有空白空间(队满、对空都是:rear == front),则队满和队空状态标记就难以区分了。
状态:
队满:(queue.rear+1)%MaxSize == queue.front
队空:queue.rear == queue.front
操作:元素入队、出队时,先移动指针,再取出元素。
入队:queue.rear=(queue.rear+1) % MaxSize; queue.data[queue.rear] = x;
出队:queue.front= (queue.front+1) % MaxSize; x = queue.data[queue.front];
循环队列中元素个数:
rear > front :r - f
rear < front :n - ( f - r )
综合:(r - f + n)%n
Coding
#include<stdio.h>
#include<malloc.h>
# define MaxSize 8
//循环队列
typedef struct{
int data[MaxSize]; //8
int front;
int rear;
}SqQueue;
//循环队列判空
void sqEmpty(SqQueue Sq)
{
if(Sq.rear == Sq.front)
{
printf("队列为空\n");
}
}
//顺序队列入队
void pushQueue(SqQueue &Sq,int data){
if((Sq.rear + 1)%MaxSize != Sq.front)//队不满才入队
{
Sq.rear = (Sq.rear + 1)%MaxSize;
Sq.data[Sq.rear]=data;
printf("%d入队成功\n",data);
}
else
{
printf("队满,%d入队失败\n",data);
}
}
//顺序队列出队
void popQueue(SqQueue &Sq)
{
if(Sq.rear==Sq.front)
{
printf("队空,元素出队失败\n");
}
else
{
printf("%d出队成功\n",Sq.data[++Sq.front]);//front++是先赋值,再运算,队首元素出队后,需要后移到下一个元素位置。
}
}
//创建循环队列
void initSqQueue()
{
SqQueue Sq;
Sq.front=Sq.rear=-1;//初始化队首队尾指针为-1;
sqEmpty(Sq);
int elem[5]={5,4,6,4,2};//设置初始化队列元素
for(int i=0;i<5;i++)
pushQueue(Sq,elem[i]);//入队
printf("\n");
for(int i=0;i<2;i++) //出队2个
popQueue(Sq);//出队
printf("\n");
for(int i=0;i<5;i++)
pushQueue(Sq,elem[i]);
}
int main()
{
initSqQueue();//循环队列
}
四、链队:
采用链式存储结构储存的队列,链队的特点:可以看作是不存在队满状态的队。
队空状态:lqu ->rear == NULL 或者 lqu -> front == NULL
操作:
进队:lqu->rear->next=p; lqu->rear=p;
出队:p=lqu->front; lqu->front=p->next; x=p->data; free(p);
#include<stdio.h>
#include<malloc.h>
//队结点
typedef struct Node{
int data;
struct Node *next;
}QNode;
//链队
typedef struct{
QNode *front;//队头指针
QNode *rear; //队尾指针
}CQueue;
//链队列判空
void cqEmpty(CQueue *Cq)
{
if(Cq->front == NULL || Cq->rear == NULL)
{
printf("队列为空\n");
}
}
//链队列入队
void pushChainQueue(CQueue *Cq,int data){
QNode *temp;
temp=(QNode *)malloc(sizeof(QNode));
temp->data=data;
temp->next=NULL;
if(Cq->rear==NULL)
{
Cq->front=Cq->rear=temp;//队列为空时,刚入队一个元素,队尾、队首都指向进队的第一个元素
temp->next=NULL;
printf("%d入队成功\n",data);
}
else
{
Cq->rear->next=temp;//将元素加入队列
Cq->rear=temp;//队尾指向该元素。
printf("%d入队成功\n",data);
}
}
//链队出队
void popChainQueue(CQueue *Cq)
{
QNode *temp;
if(Cq->front==NULL)
{
printf("队空,元素出队失败\n");
}
else
{
temp=Cq->front;
printf("%d出队成功\n",temp->data);
Cq->front=Cq->front->next;
free(temp);
}
}
//创建链队列
void initChainQueue()
{
CQueue *Cq = (CQueue *) malloc(sizeof(CQueue));
Cq->front=NULL;
Cq->rear=NULL;
int elem[5]={5,4,6,4,2};//设置初始化队列元素
for(int i=0;i<5;i++)
{
pushChainQueue(Cq,elem[i]); //元素入队
}
printf("\n");
for(int i=0;i<6;i++)
{
popChainQueue(Cq); //元素出队
}
printf("\n");
}
int main()
{
initChainQueue();//链队列
}
五、双端队列:
双端队列是一种插入和删除操作在队列两端均可进行的线性表,可以把双端队列看程栈底连在一起的两个栈,设置两个元素end1、end2分别指向队列的两端元素。
允许在一段进行插入和删除,另一端只允许删除的双端队列称为输入受限的双端队列。
允许在一段进行插入和删除,另一端只允许插入的双端队列称为输出受限的双端队列。