数据结构(11)队列之循环队列

本文介绍了循环队列的概念,解决顺序队列的假溢出问题,并探讨了循环队列的实现,包括如何判断队列满和空,以及计算当前元素个数的方法。通过具体的算式展示了在不同情况下保持正确性的策略。
摘要由CSDN通过智能技术生成

前言

昨天说到在顺序队列中,如果按照“入队则尾指针加一,出队则头指针加一”的方式实现入队出队操作,就可能出现尾指针已越界,无法插入元素;队列实际上却仍有空间的“假溢出”现象。如图

img_1

为了充分利用空间,我们可以再让尾指针循环回来,寻找插入的位置。这样,队列的这种头尾相接的顺序存储结构就被称为循环队列。

为了方便理解,书上常常将循环队列画成一个环状的结构,但是实际上它仍然是线性的。

img_2

img_3

这样,在循环队列中,判断队列已满的条件就从“查看rear值是否大于等于队列最大容量”,变成了“查看rear值是否与fount值相等”。

img_4

循环队列的实现

按照现在的设计,我们进行插入操作(新元素入队)时,需要比较rear值与fount值是否相等,如果相等说明队列已满,无法插入。但回想我们在初始化队列时,把fount值和rear值都初始化为0了。现在rear值与fount值相等就有两种情况:第一是队列是空的,可以插入元素;第二是队列已满,无法插入元素。如何区分这两种状态呢?主要有以下几种方法:

  • 设置一个flag变量标志队列的状态,当flag为0时,说明队列未满;当flag为1时,说明队列已满。
  • 与上一个类似,设置一个变量来记录队列内的元素个数,当元素个数小于队列最大容量时,说明队列为满;元素个数大于等于队列最大容量时,说明队列已满。(也可以不特别用变量来记录,而是用获取队列内元素个数的方法来获得当前的元素个数,主要看自己是怎么实现这个方法的。)
  • 一个比较特别的方法是:少用一个元素空间,当队列还有最后一个空间时,我们就认为它已经满了。什么意思呢?即设队列最大容量为m,当队列内有m-1个元素时,就认为它满了。这时候会有三种情形:

img_5
在这种前提下,当(rear == fount)时,说明队列是空的。那么判定队满的条件是什么呢?假如只考虑到 1 和 2 两种情况,很明显就是( (rear+1) == fount);但是还有 3 这种情况,这时候fount和rear相差了整整一圈,需要解决的问题是:怎样让rear循环回来?

我首先想到的办法是:当rear值等于数组最大下标时,再把它设为0就行了。当然因为涉及到与fount的比较,是设为0还是-1,自增后设置还是设置后自增等等问题还需要详细考虑,能不能行也还没有实际去做,这里就只记录下思路。

现在说下正常的方法:首先需要知道,当数A与某个数B求余时(A % B),得到的结果一定是在 0~(B-1) 这个范围内。利用求余运算的特性,我们不让rear单纯地自增,而是自增后与队列最大容量求余( (rear + 1) % MAXSIZE)。这样,当rear小于数组最大下标(MAXSIZE-1)时,rear仍是自增的;当rear值等于数组最大下标(MAXSIZE-1)时,rear就被设成了0; rear的值始终在 0~(MAXSIZE-1)范围内循环。那么,判断队满的条件就是:((rear+1)%MAXSIZE == fount)。

img_6

循环队列求当前元素个数

循环队列在求当前元素个数(即长度)时,同样有三种情形:

img_7

第一种是rear > fount,第二种是 rear < fount,第三种则是 rear == fount。

毫无疑问,如果是第一第三种情况时,只需要(rear - fount)就可以得到当前元素个数了。但是在第二种情况中,(rear - fount)得到的是负值,由于此时fount和rear相差了整整一圈,实际上应该是( (MAXSIZE+rear) - fount)。

现在使用if判断情况然后调用不同的算式固然能得到答案,但有没有能统一三种情况的方法呢?求余运算又登场了。假如我们都使用(MAXSIZE + rear - fount)这个算式,可以发现在第一第三种情况中,算式值只是多了一个MAXSIZE值而已,我们让它与MAXSIZE求余,所得的结果就是(rear - fount)。而在第二种情况中,由于算式值小于MAXSIZE,所得的结果仍是(MAXSIZE + rear - fount)。

这样,通用的计算公式就是:(rear - fount + MAXSIZE)%MAXSIZE

img_8

全部代码

SeqQueue.h
#ifndef SeqQueue_h
#define SeqQueue_h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define ElemType int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值