队列
定义:队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。
队头(Front):允许删除的一端,又称队首。
队尾(Rear):允许插入的一端。
空队列:不包含任何元素的空表
队列的顺序实现与操作
队列的顺序实现是指分配一块连续的存储单元【数组】存放队列中的元素,并附设两个指针:队头指针 front指向队头元素,队尾指针 rear 指向队尾元素的下一个位置。
#define MAXQSIZE 100 //队列可能达到的最大长度
typedef struct
{
QElemType *base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
【说明】:在初始化创建空队列的时候,为了方便,经常将front=rear=0,每当插入新的队尾元素时,rear+1,每当删除队头元素时,头指针front+1。
同时为了解决“假溢出”的问题,我们借助每次对rear和front指针操作时都取模一次MAXQSIZE,这样会自动形成一个环状空间,我们称这样的队列是循环队列。
循环队列中存在的数学关系:
初始时:Q->front = Q->rear=0。
队首指针进1:Q->front = (Q->front + 1) % MAXQSIZE。
队尾指针进1:Q->rear = (Q->rear + 1) % MAXQSIZE。
队列长度:(Q->rear - Q->front + MAXQSIZE) % MAXQSIZE。
【注意】
为了区分队空与队满,我们默认牺牲一个单元来区分此情况,约定以“队头指针在队尾指针的下一位置作为队满的标志”。
队满条件: (Q->rear + 1)%Maxsize == Q->front
队空条件仍: Q->front == Q->rear
队列中元素的个数: (Q->rear - Q ->front + Maxsize)% Maxsize
1、循环队列的初始化
【算法步骤】
① 为队列分配一个最大容量为MAXQSIZE的数组空间,base指向数组空间的首地址。
② 将头指针和尾指针置为0,表示队列为空。
Status InitQueue(SqQueue *Q)
{
Q->base=(QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
Q->front=Q->rear=0;
return OK;
}
2、求循环队列的长度
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
3、循环队列的入队
【算法步骤】
① 判断队列是否满,若满则返回ERROR。
② 将新元素插入队尾。
③ 队尾指针加1。
Status EnQueue(SqQueue *Q,QElemType e)
{
if((Q->rear+1)%MAXQSIZE==Q->front) return ERROR;
Q->base[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXQSIZE;
return OK;
}
4、循环队列的出队
【算法步骤】
① 判断队列是否为空,若空则返回ERROR。
② 保存队头元素。
③ 队头指针加1。
Status DeQueue(SqQueue *Q,QElemType *e)
{
if(Q->rear==Q->front) return ERROR;
*e=Q->base[Q->front];
Q->front = (Q->front + 1) % MAXQSIZE;
return OK;
}
5、取循环队列的队头元素
QElemType GetHead(SqQueue Q)
{
if(Q.front!=Q.rear)
return Q.base[Q.front];
}
链队列
定义:链队列是指采用链式存储结构实现的队列。通常链队列用单链表来表示。这里和线性表的单链表一样,为了操作方便起见,给链队列添加一个头节点,并令头指针始终指向头节点。
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
1、链队列的初始化
【算法步骤】
① 生成新节点作为头节点,队头和队尾指针指向此节点。
② 头节点的指针域置空。
Status InitQueue(LinkQueue *Q)
{
Q->front=Q->rear=(QNode*)malloc(sizeof(QNode)*1);
Q->front->next=NULL;
return OK;
}
2、链队列的入队
【算法步骤】
① 为入队元素分配节点空间,用指针p指向。
② 将新节点数据域置为e。
③ 将新节点插入到队尾。
④ 修改队尾指针为p。
Status EnQueue(LinkQueue *Q,QElemType e)
{
QNode *p=(QNode*)malloc(sizeof(QNode)*1);
p->data=e;
p->next=NULL;
Q->rear->next=p;
Q->rear=p;
return OK;
}
3、链队列的出队
【算法步骤】
① 判断队列是否为空,若空则返回ERROR。
② 临时保存队头元素的值,以释放空间。
③ 修改头节点的指针域,指向下一个节点。
④ 判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头节点。
⑤ 释放原队头元素的空间。
Status DeQueue(LinkQueue *Q,QElemType *e){
if(Q->front==Q->rear) return ERROR;
QNode *p=Q->front->next;
*e=p->data;
Q->front->next=p->next;
if(Q->rear==p) Q->rear=Q->front;
free(p);
return OK;
}
4、取链队列队头元素
QElemType GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)
return Q.front.next->data;
}
PTA
6-1
6-1 小孩报数(顺序循环队列版)
分数 30
作者 张庆
单位 集美大学
有若干个小孩围成一圈,现从指定的第1个开始报数,报到第 w个时,该小孩出列,然后从下一个小孩开始报数,仍是报到w个出列,如此重复下去,直到所有的小孩都出列(总人数不足w个时将循环报数),求小孩出列的顺序。
算法要求:使用顺序循环队列来存储所有小孩,报数时小孩出队,未数到w时,接着入队;数到w时,输出小孩的名字,该小孩不再入队,如此直到所有小孩出队,队列为空时停止报数。
请写出顺序循环队列的所有基本操作。
说明 :参与报数游戏的小孩人数不能超过10人。
数据结构与操作函数接口定义:
typedef char ElemType;
typedef struct // 顺序循环队列结点定义
{
ElemType *name[MaxSize]; //小孩姓名
int front,rear; //队首和队尾指针
} SqQueue;
void InitQueue(SqQueue *&q); //初始化队列;
void DestroyQueue(SqQueue *&q); //销毁队列;
bool QueueEmpty(SqQueue *q); //判定队列为空时返回true; 否则返回false;
bool enQueue(SqQueue *&q,ElemType *e); // e 入队;成功入队返回true; 否则返回false;
bool deQueue(SqQueue *&q,ElemType *&e); //出队,返回出队元素e,且成功出队返回true,否则返回false;
裁判测试程序样例:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MaxSize 11
#define N 10
int main()
{
ElemType *e;
int n,i;
SqQueue *q;
InitQueue(q);
scanf("%d",&n);
while(1)
{
char *name=(char *)malloc(sizeof(char)*N);
scanf("%s",name);
if( (strcmp("-1",name)==0)||!enQueue(q,name))
break;
}
i=n-1;
while(!QueueEmpty(q))
{
deQueue(q,e);
if(i-->0)
enQueue(q,e);
else
{
printf("%s\n",e);
i=n-1;
free(e);
}
}
DestroyQueue(q);
}
/* 请在这里填写答案 */
输入样例:
第一行:报数w;
第二行:输入若干小孩姓名,以空格符间隔,以字符串“-1”结束输入。
在这里给出一组输入。例如:
3
Jenny Mike Lily Tom Yoyo -1
输出样例:
在这里给出相应的输出。例如:
Lily
Jenny
Yoyo
Mike
Tom
答案:
void InitQueue(SqQueue*& q) // 初始化队列;
{
q = (SqQueue*)malloc(sizeof(SqQueue));
q->front = q->rear = 0;
}
void DestroyQueue(SqQueue*& q) // 销毁队列;
{
while (q->front != q->rear) {
free(q->name[q->front]);
q->front = (q->front + 1) % MaxSize;
}
free(q);
}
bool QueueEmpty(SqQueue* q) // 判定队列为空时返回true; 否则返回false;
{
return q->front == q->rear;
}
bool enQueue(SqQueue*& q, ElemType* e) // e 入队;成功入队返回true; 否则返回false;
{
if ((q->rear + 1) % MaxSize == q->front) {
return false;
}
q->name[q->rear] = e;
q->rear = (q->rear + 1) % MaxSize;
return true;
}
bool deQueue(SqQueue*& q, ElemType*& e) // 出队,返回出队元素e,且成功出队返回true,否则返回false;
{
if (q->front == q->rear) return false;
e = q->name[q->front];
q->front = (q->front + 1) % MaxSize;
return true;
}
6-2
6-2 带头结点的链队列的基本操作
分数 30
作者 黄复贤
单位 菏泽学院
实现链队列的入队列及出队列操作。
函数接口定义:
Status QueueInsert(LinkQueue *Q,ElemType e);
Status QueueDelete(LinkQueue *Q,ElemType *e);
其中 Q
和 e
都是用户传入的参数。 LinkQueue
的类型定义如下:
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode * next;
}LNode,*LinkList;
typedef struct
{
LinkList front,rear; /* 队头、队尾指针 */
}LinkQueue;
裁判测试程序样例:
#include <stdio.h>
#include<malloc.h>
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode * next;
}LNode,*LinkList;
typedef struct
{
LinkList front,rear; /* 队头、队尾指针 */
}LinkQueue;
/* 带头结点的链队列的基本操作 */
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
LinkList p;
p=(LNode*)malloc(sizeof(LNode));
p->next=NULL;
(*Q).rear=(*Q).front=p;
return OK;
}
Status List(LinkList L)
{
LinkList p;
if(!L) return ERROR;
p=L->next;
while(p)
{
printf(" %d",p->data);
p=p->next;
}
printf("\n");
return OK;
}
int QueueLenth(LinkQueue Q)
{
int n=0;
LinkList p;
if(Q.rear==Q.front)
return 0;
p=Q.front->next;
while(p)
{
n++;
p=p->next;
}
return n;
}
int main()
{
int x;
LinkQueue Q;
InitQueue(&Q);
QueueInsert(&Q,1);QueueInsert(&Q,2);QueueInsert(&Q,3);
List(Q.front );
QueueDelete( &Q,&x);
printf(" %d %d\n",x,QueueLenth(Q));
QueueDelete(&Q,&x);QueueDelete(&Q,&x);
printf(" %d %d\n",x,QueueLenth(Q));
return 0;
}
/* 请在这里填写答案 */
输出样例:
在这里给出相应的输出。例如:
1 2 3
1 2
3 0
答案:
Status QueueInsert(LinkQueue* Q, ElemType e)
{
LNode* p = (LNode*)malloc(sizeof(LNode) * 1);
p->data = e;
p->next = Q->rear->next;
Q->rear->next = p;
Q->rear = p;
return OK;
}
Status QueueDelete(LinkQueue* Q, ElemType* e)
{
if (Q->rear == Q->front)
return ERROR;
LNode* p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if (Q->rear == p) Q->rear = Q -> front;
free(p);
return OK;
}