队列+PTA

队列

定义:队列(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)

其中 Qe 都是用户传入的参数。 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;
}
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值