【数据结构学习笔记】3.2队列(Queue)
1.队列的定义
-
只允许在一端进行插入(入队),在另一端删除(出队)线性表
-
特点:先进入队列的元素先出队-First In First Out(FIFO)
2.队列的初始化
#define MaxSize 10 //定义队列中元素的最大个数
typedef struct{
Elemtype data[MaxSize]; //用静态数组存放队列元素
int front,rear; //对头指针和队尾指针
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q){
//初始时 队头、队尾指针指向0
Q.rear=Q.front=0;
}
//判断队列是否为空
bool QueueEmpty(SqQueue Q){
if(Q.rear==Q.front) //队空条件
return true;
else
return false;
}
3.入队操作
//入队
bool EnQueue(SqQueue &Q,ElemType x){
Q.data[Q.rear]=x; //将x插入队尾
Q.rear=Q.rear+1; //队尾指针后移
return true;
}
//循环队列-入队操作
bool EnQueue(SqQueue &Q,ElemType x){
if((Q.rear+1)%MaxSize==Q.front) //判断队满
return false;
Q.data[Q.rear]=x; //将x插入队尾
Q.rear=(Q.rear+1)%MaxSize; //队尾指针加1取模
return true;
}
-
用模运算将存储空间在逻辑上变成了"环状"
-
用循环队列的代价:牺牲一个存储单元
4.出队操作+队列元素的获取
//出队(删除一个队头元素,并用x返回)
bool DeQueue(SqQueue &Q,ElemType &x){
if(Q.rear==Q.front) //判断队空
return false;
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize; //队头指针后移
return true;
}
//获得队头元素的值,用x返回
bool GetHead(SqQueue Q,ElemType &x){
if(Q.rear==Q.front)
return false;
x=Q.data[Q.front];
return true;
}
-
队列元素个数公式:
(rear+MaxSize-front)%MaxSize
5.判断队空的其他方法
方案一:不浪费存储空间
-
#define MaxSize 10 //定义队列中元素的最大个数 typedef struct{ Elemtype data[MaxSize]; //用静态数组存放队列元素 int front,rear; //对头指针和队尾指针 int size; //队列当前长度 }SqQueue; -
插入成功:size++;
插入失败:size--;
-
初始化时:rear=front=0; size=0;
-
队满条件:size==MaxSize;
-
队空条件:size==0;
方案二:不浪费存储空间
-
#define MaxSize 10 //定义队列中元素的最大个数 typedef struct{ Elemtype data[MaxSize]; //用静态数组存放队列元素 int front,rear; //对头指针和队尾指针 int tag; //最近进行的是删除/插入 }SqQueue; -
每次删除操作成功时,都令tag=0
每次插入操作成功时,都令tag=1
-
初始化时:rear=front=0; size=0;
-
队满条件:front==rear&&tag==1;
-
队空条件:front==rear&&tag==0;
6.队列的链式实现(带头结点)
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}LinkNode;
typedef struct{
LinkNode *front,*rear;
}LinkQueue;
//初始化链队列(带头结点)
void InitQueue(LinkQueue &Q){
//初始时 front、rear都指向头结点
Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
Q.front->next=NULL;
}
//判断队列是否为空
bool IsEmpty(LinkQueue Q){
if(Q.front==Q.rear)
return true;
else
return false;
}
7.入队(带头结点)
//入队(带头结点)
void EnQueue(LinkQueue &Q,ElemType x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
Q.rear->next=s; //新结点插入到rear之后
Q.rear=s; //修改表尾指针
}
8.出队(带头结点)
//出队(带头结点)
bool DeQueue(LinkQueue &Q,ElemType &x){
if(Q.front==Q.rear)
return false; //空队
LinkNode *p=Q.front->next;
x=p->data; //用变量x返回队头元素
Q.front->next=p->next; //修改头结点的next指针
if(Q.rear==p) //此次是最后一个结点出队
Q.rear=Q.front; //修改rear指针
free(p); //释放结点空间
return true;
}
9.队列的链式实现(不带头结点)
//初始化链队列(不带头结点)
void InitQueue(LinkQueue &Q){
//初始时 front、rear都指向NULL
Q.front=NULL;
Q.rear=NULL;
}
//判断队列是否为空
bool IsEmpty(LinkQueue Q){
if(Q.front==NULL)
return true;
else
return false;
}
10.入队(不带头结点)
//入队(不带头结点)
void EnQueue(LinkQueue &Q,ElemType x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
if(Q.front==NULL){ //在空队列中插入第一个元素
Q.front=s;
Q.rear=s;
}
else{
Q.rear->next=s; //新结点插入到rear之后
Q.rear=s; //修改表尾指针
}
}
11.出队(不带头结点)
//出队(带头结点)
bool DeQueue(LinkQueue &Q,ElemType &x){
if(Q.front==NULL)
return false; //空队
LinkNode *p=Q.front;
x=p->data; //用变量x返回队头元素
Q.front=p->next; //修改front指针
if(Q.rear==p){ //此次是最后一个结点出队
Q.front=NULL; //front指向NULL
Q.rear=NULL; //rear指向NUL
}
free(p); //释放结点空间
return true;
}
12.双端队列的定义
-
只允许从两端插入、两端删除的线性表
-
双端队列可以退化为:栈、输入端受限的双端队列(两端都能删除但是只能从一端输入)、删除受限的双端队列(两端都能输入但是只能从一端删除)