队列概念
队列也是一种受限制的线性表,是只允许在一端进行插入,另一端进行删除的操作。
允许插入的一端被称为队尾,允许删除的一端称为队头,栈遵循先进先出的原则。就像排队一样,过来一个人就要排到队尾,而进去车厢一个人肯定从队头开始。
队的插入操作,叫做入队,队的删除操作,叫做出队。
循环队列
循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。
为了避免当只有一个元素时,队头和队尾重合时使处理变得麻烦,所以引入两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front等于rear时,此队列就成为了空队列。
判断队列是否空满
循环队列中,由于入队时尾指针向前追赶头指针;出队时头指针向前追赶尾指针,造成队空和队满时头尾指针均相等。因此,无法通过条件front==rear来判别队列是"空"还是"满"。
解决这个问题的方法至少有两种:
① 另设一布尔变量以区别队列的空和满;
②另一种方式就是数据结构常用的:
在数组中留出一个空间,当出现下图a的情况就认为队列已满,不允许出现图b的情况:
由于rear可能比front大,也可能比front小,队满时就满足:(rear+1)%n==front,n为队列长度(所用数组大小),由于rear,front均为所用空间的指针,循环只是逻辑上的循环,所以需要求余运算。
循环队列的相关条件和公式
队尾指针是rear,队头是front,其中QueueSize为循环队列的最大长度
1.队空条件:rear==front
2.队满条件:(rear+1) %QueueSIze==front
3.计算队列长度:(rear-front+QueueSize)%QueueSize
4.入队:(rear+1)%QueueSize
5.出队:(front+1)%QueueSize
链队列
队列的链式存储结构,实际上就是线性表的单链表,只不过它只能尾进头出而已,我们简称为链队列。
入队操作的时候,实际上就是在链表的尾部插入结点,出队操作的时候,实际上就是头结点的后继结点出队,将头结点的后继结点改为它后面的结点,如果链表除了头结点以外只剩下一个元素,则需要将rear指向头结点。
在队列为链栈时,除了初始构造是皆为空外,当这两个指针再次相遇时,这个链队列的元素为一个。
在确定队列长度最大值的情况下,建议利用循环队列,如果无法预估队列长度,可以用链队列。
例题
在链队列中,即使不设置尾指针也能进行入队操作, 若使用不设置尾指针的链表作为链队列的存储结构,在进行入队操作的时候需要遍历整个链队列至队尾,然后在进行插入。这当然是可行的,只是效率有所下降。
某带链的队列初始状态为 front=rear=NULL 。经过一系列正常的入队与退队操作后, front=rear=10 。该队列中的元素个数为1,在队列为链栈时,除了初始构造是皆为空外,当这两个指针再次相遇时,这个链队列的元素为一个。