在“队列”(Queue
)这种数据结构中,数据项是先进先出(FIFO:first in first out
)。队列的容量可以有限,也可以是无限的。
一、基于数组的Queue实现
一般情况下,对于Queue而言,最核心的操作是:插入队列(enqueue
)、移出队列(dequeue
)。因为在队列中,插入操作是插入到队列的最后,而移出操作是移出队列的头部元素。因此我们通常会使用两个变量front
(队头指针)和rear
(队尾指针)记录当前元素的位置。
假设我们有一个容量有限队列,用于存放字母,如下图所示:
当我们要插入一个元素时,因为总是插入到队列的最尾部,所以插入的位置是rear+1的位置。
当我们要移出一个元素时,是从队头指针front的位置开始移除(因为Queue头部的元素是最先加入进来的,根据FIFO原则,应该最先移除)。当移除一个元素之后,front应该加1,因为移出一个元素之后,下一个元素就变成了第一个元素。例如现在我们移出了5个元素:
当移出5个元素之后,队头指针就移动到了字母F的位置,前五个位置空下来了。队尾指针rear不变。
现在问题来了:队列头部移出的几个元素,位置空下来了。当我们添加元素的时候,从队尾开始加,当添加到最后一个位置时,怎么办?不让添加时不合理的,毕竟前几个位置已经空下来了。我们的期望是,当一个位置上的元素被移出之后,这个位置是可以被重复使用的。而我们这里讨论的是有限容量的数据,如果我们还继续添加元素,那么就要往队列头部来添加。
这实际上就涉及到了循环队列的概念。也就是当队尾指针到了数组的最后一个下标时,下一个位置应该就是数组的首部。
因此,当队尾指针指向数组顶端的时候,我们要将队尾指针(rear)重置为-1,此时再加1,就是0,也就是数组顶端例。如我们又添加了5个字母,那么结果应该如下图:
代码实现:
测试:
二、Java中的Queue
java中定义了一个java.util.Queue接口,定义了如下方法:
可以发现这些方法都是两两成对的。
Queue还有一个子接口BlockingQueue
,主要定义了一些在并发环境下,方法应该具有特性。
Java中还提供了一个java.util.Deque双端队列(deque,全名double-ended queue),就是队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。
这个我们就不细说了,因为在实际开发中,Deque远远没有Queue实用。
前面我们讲解的Queue是基于数组实现了,实际上,Queue也可以基于链表(LinkedList)实现,例如添加元素的时候总是调用addFisrt方法,移除元素的时候总是调用removeLast方法,则实现了FIFO的功能,因此链表是可以实现Queue的功能的,这也是我们在前面说链表是除了数组外另一种最广泛应用的基础数据结构的原因。
事实上,java中的LinkedList就实现了Deque接口。
因此LinkedList具有Deque和Queue的所有功能。
原文:https://www.cnblogs.com/muzhongjiang/p/13672524.html