和顺序栈相类似,队列也可以简单地用一维数组
表示。设数组名为queueArray
,其下标下界为0,上界为n-1。在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素以外,还需要设置两个指针front和rear分别指示队列的队头元素和队尾元素的位置。
空队列
队列中元素的数目等于零称为空队列,初始化空队列时,设front=rear=0
,如图3.7(a)
所示。
入队时rear的变化
入队时将队尾指针rear增加,即rear=rear+1
,再将新元素按rear指示位置加入,如图3.7(b)、(c)、(d)所示,当A入队时,rear指向1,当B入队后,rear指向2,而当C、D入队后,rear指向4。
出队时front的变化
出队时将队头指针增加1,即front=front+1
,再将front所指的元素取出,如图3.7(e)、(f)所示,当A出队时,front指向1,当B出队时,front指向2。
头指针与尾指针
因此,在非空队列中,头指针
始终指向队列头元素的前一个位置,尾指针
始终指向队列尾元素的位置
队列溢出
如图3.7(g)
所示,元素E出队后,尾指针rear指向尾元素E的位置。如果当前为队列分配的最大空间为6,则此时,队列就不可以再增加新的队尾元素,否则会因数组越界而导致程序代码被破坏,这就是队列的溢出,如图3.7(h)
所示。
通过上面队列定义的操作我们发现一个问题,由于队列的入队、出队操作是在两端进行的,随着元素的不断插入、删除,两端都向后移动,队列会很快移动到数组末端造成溢出,而前面的单元无法利用。如图3.7(h)
所示,虽然队列中还有三个位置(索引值为0、1、2)有剩余空间,但无法插入新入队元素。这种情况称为假溢出
。
对于这个问题,我们提出了两种解决办法。
(1)每次删除一个元素后,将整个队列向前移动一个单元,保持队列头总固定在数组的第一个单元。只是这样的话,我们每次删除元素时,都要执行一次循环操作,移动队列中所有元素向前一个单元,那样造成了系统的额外开销。
(2)将顺序队列的存储区假想为是一个头尾相连的圆环,当队尾指示器rear到达数组的上限时,如果还有数据元素入队并且数组的第0个空间空闲时,队尾指示器rear指向数组的0端,如图3.8(d)、(e)所示。当队头指示器front到达数组的上限时,如果还有数据元素出队,队头指示器front指向数组的0端,如图3.8(g)、(h)所示。这样做,出队元素空出的空间可被重新利用,除非整个数组单元真地全部被队列元素占用,否则不会出现溢出,从而解决了假溢出
问题。虽然此时物理上的队尾在队首之前,但逻辑上队首仍在前,进队和出队仍按“先进先出”的原则进行,通常把这种特殊结构的队列称为循环队列
。