循环队列与链队列的简单实现

原创 2018年04月17日 15:23:19

一、循环队列

a、概念

    为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。


    通过上图可以看出,如果使用顺序表作为队列的话,当处于d状态则不能继续插入新的队尾元素,否则会因为数组越界而导致程序代码被破坏。


    所以产生了由链表实现的循环队列,只有队列未满时才可以插入新的队尾元素。判断循环队列是空队列还是满队列依据:头尾指针相同就是空,尾指针的下一个是头指针就是满。

b、代码及运行结果

#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define MAXQSIZE 5
typedef int Status;
typedef int QElemType;
typedef struct Node
{
    QElemType *base; //初始化动态分配存储空间
    int front;
    int rear;
} SqQueue;

Status InitQueue(SqQueue *Q)
{
    Q->base = (QElemType *)malloc(MAXQSIZE * sizeof(QElemType));
    if (!Q->base)
        return ERROR;
    Q->front = Q->rear = 0;
    return OK;
}

Status EnQueue(SqQueue *Q, QElemType elem)
{
    //队列为空时 1%5==1,队列满时(4+1)%5==0,最多容纳4个元素
    if ((Q->rear + 1) % MAXQSIZE == (Q->front))
        return ERROR;
    Q->base[Q->rear] = elem;
    Q->rear = (Q->rear + 1) % MAXQSIZE; //rear始终在0-5中循环
    return OK;
}

Status OutQueue(SqQueue *Q, QElemType *e)
{
    if (Q->front == Q->rear)
        return ERROR;
    *e = Q->base[Q->front];
    Q->front = (Q->front + 1) % MAXQSIZE;
    return OK;
}

Status PrintQueue(SqQueue Q)
{
    printf("the queue is:");
    for (int i = Q.front; i < Q.rear; ++i)
        printf("%d ", Q.base[i]);
    return OK;
}
int main()
{
    SqQueue queue;
    QElemType elem;
    int i;
    while(!InitQueue(&queue));
    EnQueue(&queue,1);
    EnQueue(&queue,2);
    EnQueue(&queue,3);
    EnQueue(&queue,4);
    EnQueue(&queue,5);//队列已满,无效入队
    printf("\noutput:");
    scanf("%d", &i);
    while(i != 0)
    {
        OutQueue(&queue, &elem);
        i--;
    }
    PrintQueue(queue);
    return OK;
}

二、链队列

a、概念

    队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列。

 当队列为空时,front和rear都指向头结点;

    

    入队:在队列尾部插入结点;

    

    出队:头结点的后继结点(队头)出队,将头结点的后继改为他后面的结点,若链表除头结点外只剩一个元素时,则需将rear指向头结点。

    一般情况下,链队列的出队图示:

    

b、代码及运行结果

  
#include<stdio.h>  

#include<stdlib.h>  

//链队列结点结构  

typedef struct QNode{  

    int data;  

    struct QNode *next;  

}QNode;  

//链队列结构  

typedef struct LiQueue{  

    QNode *front;  

    QNode *rear;  

}LiQueue;  

//创建链队列  

LiQueue initQueue(){  

    LiQueue *lq=(LiQueue *)malloc(sizeof(LiQueue));  

    if(lq ==NULL){  

        return *lq;  

    }  

    lq->front=lq->rear=NULL;  

    return *lq;  

}  

//判断链队列是否为空  

int isEmpty(LiQueue *lq){  

    if(lq->front==NULL || lq->rear==NULL){  

        return 0;  

    }else{  

        return 1;  

    }  

}  

//元素进链队列  

void enQueue(LiQueue *lq,int x){  

    QNode *p;  

    p=(QNode *)malloc(sizeof(QNode));  

    p->data=x;  

    p->next=NULL;  

    if(lq->rear==NULL){  

        lq->front=lq->rear=p;//如果第一次插入则设置头指针和尾指针为p  

    }else{  

        lq->rear->next=p;//链队列的尾部插入p  

        lq->rear=p;//设置链队列的尾指针指向p  

    }  

}  

//元素出链队列  

int deQueue(LiQueue *lq,int *y){  

    QNode *p=lq->front;  

    if(lq->rear==NULL || lq->front==NULL){  

        return 0;  

    }  

    if(lq->front==lq->rear){  

        lq->front=lq->rear=NULL;  

    }else{  

        lq->front=lq->front->next;  

    }  

    *y=p->data;  

    free(p);  

    return 1;  

}  

//打印链队列  

void printQueue(LiQueue lq){  

    if(lq.front==NULL || lq.rear==NULL){  

        return;  

    }  

    while(lq.front!=NULL){  

        printf("%d\n",lq.front->data);  

        lq.front=lq.front->next;  

    }  

}  

int main(void){  

    int y=0;  

    LiQueue lq=initQueue();  

    enQueue(&lq,1);  

    enQueue(&lq,2);  

    enQueue(&lq,3);  

    enQueue(&lq,4);  

    enQueue(&lq,5);  

    //deQueue(&lq,&y);  

    printQueue(lq);  

    printf("出队列元素=%d\n",y);  

return 0;

}  

三、循环队列和链队列的比较

 从时间上,其实它们的基本操作都是常数时间,即都为0(1)的,不过循环队列是事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销,如果入队出队频繁,则两者还是有细微差异。

 对于空间上来说,循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题。而链队列不存在这个问题,尽管他需要一个指针域,会产生一些空间上的开销,但也可以接受。所以在空间上,链队列更加灵活。

 总的来说,在可以确定队列长度的情况下,建议用循环队列;不能预估队列长度时,建议用链队列。


RabbitMQ

rabbitmq使用场景,安装,vhost配置,简单队列,工作队列work queues,消息应答ack与消息持久化durable,publish/subscribe发布订阅模式,routing路由模式,topic主题模式,消息确认机制(事务+confirm),spring集成
  • 2018年04月12日 09:22

循环队列实现(C语言)

#ifndef __QUEUE_H_ #define __QUEUE_H_ typedef int DataType; ///////////////////////////////...
  • changyourmind
  • changyourmind
  • 2016-10-27 21:37:22
  • 1503

循环队列及C语言实现<一>

循环队列是为了充分利用内存,进行数据操作的一种基本算法。具体实现方式可划分为:链式队列和静态队列,这里所谓的静态是指在一片连续的内存区域进行数据操作。本文只讲述静态队列,也是最简单的实现方式,静态队列...
  • JAZZSOLDIER
  • JAZZSOLDIER
  • 2016-09-21 22:34:11
  • 5219

队列---循环队列与链队列比较

对于循环队列与链队列的比较,可以从两方面来考虑:1、从时间上,其实它们的基本操作都是常数时间,即都为0(1)的,不过循环队列是事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一...
  • will130
  • will130
  • 2015-10-21 23:11:45
  • 1100

普通队列,循环队列以及链队列的相关操作

普通队列,循环队列以及链队列的相关操作
  • ismahui
  • ismahui
  • 2017-08-01 16:37:49
  • 508

循环队列与链队列的优劣势

循环队列与链队列的优劣势  循环队列、链队列分别什么时候用 对于循环队列与链队列的比较,可以从两方面来考虑: 从时间上,其实它们的基本操作都是常数时间,即都为0(1)的,不过循环...
  • qq_15037231
  • qq_15037231
  • 2016-07-30 20:41:09
  • 1108

循环队列和链式结构队列

一、循环队列的基础知识 1,循环队列有几个参数需要确定:       有两个参数,front和rear 2,循环队列各个参数的含义 (1)队列初始化时,front和rear值都为零; ...
  • u010949971
  • u010949971
  • 2017-02-27 13:22:04
  • 1178

数据结构_线性表_顺序队列_循环队列_链队列

个位看管,由于队列操作相对简单,我啥也不多说,直接上代码,欢迎验证!!!#pragma mark --abstract //队列(queue)是只允许在表的一端进行插入,在表的另一端进行删除的线性表,...
  • lcg910978041
  • lcg910978041
  • 2016-05-09 10:19:44
  • 859

链队列、循环队列的实现(初始化、出队、入队、取队头元素、判空)

链队列 #include #include //结点的结构体定义 typedef int DataType; typedef struct qnode { DataType data; stru...
  • qq_38004995
  • qq_38004995
  • 2017-04-09 15:27:56
  • 2771

循环队列的定义及操作

#include #include #define MAXSIZE 50 typedef struct { int element[MAXSIZE]; int front; //...
  • potential1
  • potential1
  • 2017-05-21 18:32:15
  • 848
收藏助手
不良信息举报
您举报文章:循环队列与链队列的简单实现
举报原因:
原因补充:

(最多只允许输入30个字)