顺序循环队列与链队列

简介: 今天学习了队列,一种是顺序循环队列,一种是链队列,我个人认为链队列相对好用一点,毕竟链队列不用考虑“假溢出”的问题,下面是我整理的关于队列的一些基本操作

我们先来看个问题:
【问题描述】
实现循环队列的基本操作。(循环队列最大长度不超过20)
【输入形式】
输入若干个整数(以空格分隔),其中0表示做出队操作,不为0的整数为入队元素。
【输出形式】
依次输出队列的全部元素,若队列为空,则输出“empty”
【样例输入1】
1 2 3 4 5 6
【样例输出1】
1 2 3 4 5 6
【样例输入2】
1 2 3 0 0 4 0 5
【样例输出2】
4 5
【样例输入3】
1 0 2 0 3 0
【样例输出3】
empty
【样例输入4】
1 0 2 0 0 3 0 0 0
【样例输出4】
empty
下面我们将分别通过顺序循环队列和链队列来实现以上操作

一、顺序循环队列

顺序循环队列需要两个指针,一个用来入队,一个用来出队
顺序循环队列是个在数组中移动的队列
顺序循环队列主要要考虑“假溢出”的问题,为了防止“假溢出”,我们通过(front+1)%MAX来实现

1.1 初始化一个顺序循环队列

#include<stdio.h>
#include<malloc.h>
#define MAX 10
typedef struct Queue{
    int *base;       //可以理解为一个数组
    int front;       //指向队头的指针   可以理解为数组的下标
    int rear;        //指向队尾的指针   可以理解为数组的下标
    int len;         //队列的长度,方便打印队列
}Queue,*PQueue;
int Init_Queue(PQueue Q){
    Q->base=(int *)malloc(MAX*sizeof(int));   //初始化分配一个空间
    Q->front=Q->rear=0;                //初始化队头队尾在一起
    Q->len=0;                          //初始化队列长度为0
    return 1;
}

1.2 判断队列是否为空

int Empty_Queue(PQueue Q){
    if(Q->front==Q->rear)     //当队头和队尾指针在一起的时候,说明是个空队
    return 1;
    else
    return 0;
}

1.3 入队

入队前一定要先判断队列是否已经满了,满了就不能再入队了

int Push_Queue(PQueue Q,int e){
    if((Q->rear+1)%MAX==Q->front) return 0;    //首先要判断队列是否满了
    Q->base[Q->rear]=e;           //满了无法入队,没满可以入队
    Q->rear=(Q->rear+1)%MAX;      //这个方法可以让队列成为循环队列
    Q->len++;                     //每次入队队列长度增加1
    return 1;
}

1.4 出队

出队前一定要判断队列是否已经空了,如果队列空了,那么就没办法出队了

int Pop_Queue(PQueue Q,int *e){
    if(Q->front==Q->rear) return 0;   //出队前要先判断是否队空
    *e=Q->base[Q->front];             //队列不空可以出队
    Q->front=(Q->front+1)%MAX;        //这个方法可以循环出队
    Q->len--;                         //出队后队长减1
    return 1;
}

1.5 打印队列

int Print_Queue(PQueue Q){
    int i;
    for(i=0;i<Q->len;i++){
        printf("%d ",Q->base[Q->front+i]);    //将队列打印出来
    }
    printf("\n");
    return 1;
}

1.6 代码实现

1.6.1 完整代码

#include<stdio.h>
#include<malloc.h>
#define MAX 10
typedef struct Queue{
    int *base;
    int front;
    int rear;
    int len;
}Queue,*PQueue;
int Init_Queue(PQueue Q){
    Q->base=(int *)malloc(MAX*sizeof(int));
    Q->front=Q->rear=0;
    Q->len=0;
    return 1;
}
int Empty_Queue(PQueue Q){
    if(Q->front==Q->rear)
    return 1;
    else
    return 0;
}
int Push_Queue(PQueue Q,int e){
    if((Q->rear+1)%MAX==Q->front) return 0;
    Q->base[Q->rear]=e;
    Q->rear=(Q->rear+1)%MAX;
    Q->len++;
    return 1;
}
int Pop_Queue(PQueue Q,int *e){
    if(Q->front==Q->rear) return 0;
    *e=Q->base[Q->front];
    Q->front=(Q->front+1)%MAX;
    Q->len--;
    return 1;
}
int Get_Queue(PQueue Q,int *e){
    if(Q->front==Q->rear) return 0;
    *e=Q->base[Q->front];
    return 1;
}
int Print_Queue(PQueue Q){
    int i;
    for(i=0;i<Q->len;i++){
        printf("%d ",Q->base[Q->front+i]);
    }
    printf("\n");
    return 1;
}
int main(){
    Queue Q;
    int e;
    Init_Queue(&Q);
    while(scanf("%d",&e)==1){
        if(e==0){
            Pop_Queue(&Q,&e);
        }else{
            Push_Queue(&Q,e);
        }
    }
    if(Empty_Queue(&Q)==1){
        printf("empty\n");
    }else{
        Print_Queue(&Q);
    }
    return 0;
}

1.6.2 运行结果

1.png

二、链队列(带头结点单链表)

我们用的是带头结点的单链表,方便出队
链队列需要两个指针,分别用来入队和出队
链队列不用考虑“假溢出”问题,操作起来更加方便

2.1 初始化一个链队列

#include<stdio.h>
#include<malloc.h>
typedef struct Node{       //每个结点
    int data;
    struct Node *next;
}Node,*PNode; 
typedef struct Queue{      //保存两个指针
    PNode front,rear;
}Queue,*PQueue;
int Init_Queue(PQueue Q){
    PNode P=(PNode)malloc(sizeof(Node));
    P->next=NULL;
    Q->front=Q->rear=P;    //初始队尾指针在队头指针位置
    return 1;
}

2.2 判断队列是否为空

int Empty_Queue(PQueue Q){
    if(Q->front==Q->rear)    //当队尾指针在队头指针处时,队列为空
    return 1;
    else
    return 0;
}

2.3 入队

链队列入队不用考虑“假溢出”问题,操作起来方便

int Push_Queue(PQueue Q,int e){
    PNode Pnew=(PNode)malloc(sizeof(Node)); //新建一个结点,用于入队
    Pnew->next=NULL;     
    Pnew->data=e;   
    Q->rear->next=Pnew;      //入队操作只用尾指针rear
    Q->rear=Pnew;
    return 1;
}

2.4 出队

int Pop_Queue(PQueue Q,int *e){
    if(Q->front==Q->rear) return 0;     //出队先判断是否队空
    *e=Q->front->next->data;
    if(Q->front->next==Q->rear){        //当只剩一个有效结点的时候,为了避免尾指针丢失
        Q->front->next=NULL;
        Q->rear=Q->front;               //我们删除结点后要让尾指针指向头结点
    }else{
        Q->front->next=Q->front->next->next;   
    }
    return 1;
}

2.5 打印队列

int Print_Queue(PQueue Q){
    PNode P=Q->front->next;
    while(P){
        printf("%d ",P->data);    //和打印单链表类似
        P=P->next;
    }
    printf("\n");
}

2.6 代码实现

2.6.1 完整代码

#include<stdio.h>
#include<malloc.h>
typedef struct Node{
    int data;
    struct Node *next;
}Node,*PNode;
typedef struct Queue{
    PNode front,rear;
}Queue,*PQueue;
int Init_Queue(PQueue Q){
    PNode P=(PNode)malloc(sizeof(Node));
    P->next=NULL;
    Q->front=Q->rear=P;
    return 1;
}
int Empty_Queue(PQueue Q){
    if(Q->front==Q->rear)
    return 1;
    else
    return 0;
}
int Push_Queue(PQueue Q,int e){
    PNode Pnew=(PNode)malloc(sizeof(Node));
    Pnew->next=NULL;
    Pnew->data=e;
    Q->rear->next=Pnew;
    Q->rear=Pnew;
    return 1;
}
int Pop_Queue(PQueue Q,int *e){
    if(Q->front==Q->rear) return 0;
    *e=Q->front->next->data;
    if(Q->front->next==Q->rear){
        Q->front->next=NULL;
        Q->rear=Q->front;
    }else{
        Q->front->next=Q->front->next->next;
    }
    return 1;
}
int Get_Queue(PQueue Q,int *e){
    if(Q->front==Q->rear) return 0;
    *e=Q->front->next->data;
    return 1;
}
int Print_Queue(PQueue Q){
    PNode P=Q->front->next;
    while(P){
        printf("%d ",P->data);
        P=P->next;
    }
    printf("\n");
}
int main(){
    Queue Q;
    Init_Queue(&Q);
    int e;
    while(scanf("%d",&e)==1){
        if(e==0){
            Pop_Queue(&Q,&e);
        }else{
            Push_Queue(&Q,e);
        }
    }
    if(Empty_Queue(&Q)==1){
        printf("empty\n");
    }else{
        Print_Queue(&Q);
    }
    return 0;
}

2.6.2 运行结果

2.png

三、总结

1.顺序循环队列入队和出队都要考虑“假溢出”的问题

2.链队列出队时要考虑是否是最后一个有效结点,避免尾结点的丢失

3.相比之下,链队列不用考虑“假溢出问题”,在实际应用中操作起来跟方便

目录
相关文章
|
机器学习/深度学习
循环队列的实现
循环队列的实现
用循环链表实现队列
用循环链表实现队列
95 0
|
7月前
循环队列详解
循环队列详解
|
存储
循环队列来了解一下!!
循环队列来了解一下!!
55 0
|
存储 机器学习/深度学习 人工智能
线性表的顺序实现
线性表的顺序实现
SWUSTOJ 965: 循环队列
SWUSTOJ 965: 循环队列
115 0
|
存储 缓存 算法
【数据结构】队列(循环队列和链队列)详细讲解各种操作
【数据结构】队列(循环队列和链队列)详细讲解各种操作
945 0
顺序循环队列和链式存储队列(带头结点和不带头结点)
顺序循环队列和链式存储队列(带头结点和不带头结点)
|
C++
C++实现线性表 - 05 队列(数组实现)
今天我们来学习一下队列结构,这也是我们讲线性表的最后一个部分了,这里会分成两节来讲,先讲数组的实现,再讲链表的实现。由于双端队列是包含了单端队列的操作,所以我们这里为了讲的更全一些,代码实现为双端队列。
144 0
C++实现线性表 - 05 队列(数组实现)