循环队列的实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了循环队列的实现相关的知识,希望对你有一定的参考价值。

   队列的一个非常重要的特点就是:只允许在队列的头部进行删除操作,只允许在队列的尾部进行插入操作。

   所以,很明显,队列这种结构需要两个指针,一个指针指向队列的头部,一个指针指向队列的尾部。既然队列这种结构也是用来存放数据的,当有一个数据存入队列中时,指向尾部的指针就向后加1,当删除一个元素时,头指针就向后加1,由于我们定义当队列为空时,指向头部的指针和指向尾部的指针重合,所以,当删除到剩余最后一个元素时,头指针front和尾指针rear就重合了,这样会和我们定义的队列为空两指针重合相矛盾。所以,我们要做的就是,将尾指针rear指向队列尾部的下一个位置。这样,问题就解决了。

   如果有数据插入,我们可以将rear+1,当数据不需要而要将其删除时,我们将front+1,直到rear指向队列尾部的下一个位置,已经没有位置可以放新的元素了,那么此时队列真的已经满了吗?当然没有,因为删除一个元素时,front++,所以,在front前面还有位置可以放元素,所以此时,这种虚假的队列满的情况,称之为“假溢出”。

   那么如何解决这个假溢出的现象呢?当然有办法,就是通过循环队列,当rear指针指向最后一个位置时,就将它置为0,指向队列头部。那假设我们有了一个循环队列,当rear向后自增,又从0开始接着向后自增,直到和front重合时,队列满。这样一来,我们又带来一个问题,我们怎么判断rear==front到底是队列为空还是队列是满的呢?解决的办法就是空出一个单元,不存放任何数据,也就是当rear+1 == front时,就意味着满队列了。所以,判断满队列的条件就是:

( reat + 1 ) % QueueSize == front;

此时,就认为是满队列状态。

   那么我该如何计算队列的长度呢?因为rear有可能比front大也有可能比front小,我该如何确定队列的元素个数呢?第一种情况,rear > front。此时,只要将rear - front就可以计算出队列的长度了。

技术分享

由图所示,图中有2个元素,a3和a4。所以,我们要计算队列长度,只需将rear-front,就可以得出结果了。第二种情况,rear < front。如图所示:

技术分享

当碰到这种出现假溢出形式的时候,我们该如何计算队列的长度呢?很明显,此时,队列长度的计算分为两段,一段是front之后的元素,一段是rear之前的元素,计算A3和A4这两个元素,我们只需(QueueSize - front)这样以来,就算出来了,此时QueueSize的值为5,那么(5 - 3 )的值为2,所以,第一段元素的长度为2,第二段元素长度,只需要(0 + rear ) 就可以了,也就是(0 + 2 ),此时值为2,所以,队列真正的长度就为(2 + 2 = 4 ), 那么队列的长度就计算出来了。

因为有两种情况,所以,为了实现通用,就有一个标准的计算队列长度的公式:

( rear - front + QueueSize ) % QueueSize

   接下来,就来定义一个循环队列的结构:

typedef int QElemType;

typedef struct{

    QElemType data[MAXSIZE];
    int front;
    int  rear;
}SqQueue;

如果要初始化一个队列,我们该如何做呢?

Status InitQueue ( SqQueue *Q ){

    Q->front = 0;
    Q->rear = 0;
    
    return OK;
}

求循环队列的长度

int QueueLength ( SqQueue Q ){

    return ( Q.rear - Q.front + MAXSIZE ) % MAXSIZE;

}

循环队列元素的插入

Status EnQueue ( SqQueue *Q, QElemType e ){

    if ( ( Q->rear + 1 ) % MAXSIZE == front )
        return ERROR;
    
    Q->data[Q->rear] = e;
    Q->rear = ( Q->rear + 1 ) % MAXSIZE;
    
    return OK; 

}

循环队列元素的删除

Status DeQueue ( SqQueue *Q, QElemType *e ){

    if ( Q->rear == Q->front )
        return ERROR;
        
    *e = Q->data[Q->front];
    Q->front = ( Q->front + 1 ) % MAXSIZE;
    
    return OK;

}


本文出自 “梵高说我脑子有病” 博客,请务必保留此出处http://chen0547.blog.51cto.com/12489941/1968166

以上是关于循环队列的实现的主要内容,如果未能解决你的问题,请参考以下文章

用java实现循环队列?

最强解析面试题:Goland 循环队列实现

如何只用队头指针实现顺序循环队列?

go语言循环队列的实现

爬虫代码实现七:实现高低级队列循环抓取

数据结构学习笔记——顺序存储结构实现循环队列