队列
定义:队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列(Queue)是一种先进先出(First In First Out)的线性表,简称FIFO。
允许插入的一端叫做队尾,删除的一端叫做队头。
同样是线性表,队列也有类似的操作。不同的是队列是在队尾插入数据,在队头删除数据。
顺序队列
队列的基本操作
1. getSize() 获取队列中有效元素的个数
2. isEmpty() 判断是否为空
3. clear() 清空队列
4. enqueue() 入队
5. dequeue() 出队
6. getFront() 获取队首元素
7. getRear() 获取队尾元素
空队列:
这是一个长度为6空队列,此时队尾指针在头部。当我们向队列中插入元素时,效果如下图。
插入数据时,队尾指针向后移动
插入一个数据,队尾指针移动到下标加1的位置
当我们插入两个数据时,我们要删除一个数据,那么数据要从队头的位置开始删除,即现在下标为0的位置的数据要出队,下标为1的数据就要移动到下标为0的位置,同时队尾指针也要移动到下标为0的位置,即向左移动。
顺序存储的队列是是由ArrayList实现的。
即在数据元素入队的时候,相当于在 ArrayList表尾添加元素,时间复杂度为O(1)。
即在数据元素出队的时候,相当于在 ArrayList表头添加元素,时间复杂度为O(n)。
出队的时间复杂度为O(n)是因为当前只有队尾指针在移动,而队头始终不动,而且还要保证数据的连续性,所以出队的时间复杂度为O(n)。
为了解决出队的时间复杂度为O(n)的问题,我们有了循环队列这个概念。
这里我们添加了队头指针,队头指针指向队列中第一个元素,队尾指针指向队列中最后一个元素。
当我们引入队头指针时,出队数据元素时,队头指针向后移动1个下标的位置即可。
这样出队的时间复杂度就成了O(1)。
但是这样优化的问题就是入队出队的时候数据元素是往后移动的,前面的部分位置就空下来了。且尾指针(Rear)不能继续后移了。
为了解决上面的问题,我们让头指针和尾指针走到表尾的时候需要后移就重新指向头部。
但是这个时候如何判断队列是满的还是空的?
但是这个时候我们不难发现,当队列已满和队列为空时,判定的条件都可以是(R+1)%n==F
因为这个条件同时满足两种情况,属于不严谨的情况,所以我们要再次优化。
我们让尾指针始终指向数组中元素的后一个下标的位置,但这个位置里什么都不存,为null。
这样就可以解决判定队列已满和为空的条件重复了。
我们不难看出这个时候队列为空,判断的条件是R==F。
队列已满时,判断的条件是(R+1)%n==F。