队列学习笔记

队列和栈都是一种运算受限的线性表。只允许在表的一端进行插入,而在另一端进行删除。允许删除的叫做队首(front),允许插入的叫做队尾(rear)。即先进先出原则,如同排队取票。

1. 非循环顺序队列

队列的顺序存储结构称为顺序队列。和顺序表一样,顺序队列,顺序队列也需要用一个数组存放当前队列中的元素。由于队头和队尾都是变化的,所以需要设置两个指针,分别指示当前队头元素和队尾元素在数组中的位置。

struct sequeue
{
    datatype data[max_size];
    int front,rear;
};              /*顺序队列的类型*/
sequeue *sq     /*sq是顺序队列的指针*/

为方便起见,我们规定头指针front总是指向队头元素的前一个位置,尾指针指向当前队尾元素的位置,一开始队列的头指针和尾指针指向向量空间下界的前一个位置,在此设置为-1,若不考虑溢出,

  • 则入队操作可表示为
sq->rear++;                     /*尾指针加1*/
sq->data[sq->rear]=element;     /*元素element 入队*/    
  • 出队操作可表示为
sq->front++;

显然当 sq->front==sq->rear时,队列为空。队列为空时进行出队操作产生下溢,队满的条件是sq->rear-sq->front==maxsize,队满时进行入队操作就会导致上溢
但是当前队列尾指针等于数组的上界即(sq->rear==maxsize-1)时依然会出现上溢。由此导致出现一种新现象即假上溢。因此需要在删除队首元素时将剩下的所有元素全部向队首迁移一位,由此又会导致队列删除元素时操作时间复杂度上升O(sq->rear-sq->front),由此引出一种新概念,循环队列。

2. 循环顺序队列

通常采用的方法是设想sq->data[maxsize]是一个首尾相接的圆环,即sq->data[0]接在sq->data[maxsize-1]之后,将这种队列称为循环队列。若当前尾指针等于数组的上界,再做入队操作时,令尾指针等于数组的下界,这样就能克服假上溢现象,因此循环列表下的尾指针加1可以表示为:

if(sq->rear+1>=maxsize)
{
    sq->rear=0;
}
else
{
    sq->rear++;
}

用模运算的情况下上述操作可以更间接地描述为

sq->rear = (sq->rear+1)%maxsize;

同样的出队列运算也可以用模运算来表示

sq->front = (sq->front+1)%maxsize;

若某元素出队列之后头指针追上尾指针,即sq->front ==sq->rear,则队列为空,若某元素进队列之后尾指针追上头指针即sq->rear ==sq->front,则队列满,因此sq->rear ==sq->front无法判断是否队空或者队满。
对此有两种解决办法:其一就是引入一个标识变量以区别队空或是队满,其二就是入队操作时检查尾指针加1之后会不会等于头指针即

if((sq->rear+1)%maxsize==sq->front;)

计算队列元素的个数的时有两种情况
1.当front < rear时,由于我们规定头指针front总是指向队头元素的前一个位置,尾指针指向当前队尾元素的位置,因此元素个数为rear-front;
2.当rear< front时,我们可以将整个队列分为两段分别是(rear-0+1)和(maxsize-1-front),即(maxsize+rear-front)如图所示这里写图片描述
两者结合即有

(maxsize+rear-front)%maxsize

猜你喜欢

转载自blog.csdn.net/qq_36130482/article/details/79431252