一、 基本概念
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First in First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。
假设队列是q=(a1,a2,…,an),那么a1就是队头元素,而an是队尾元素。这样我们就可以删除时,总是从a1开始,而插入时,列在最后。这也比较符合我们通常生活中的习惯,排在第一个的优先出列,最后来的当然在队伍的最后。
二、存储结构及自定义实现基本操作
队列既然是一种线性表,所以线性表的顺序存储和链接存储结构同样适用于队列。
1、顺序存储——数组实现
入队时,通过tail的位置判断队列是否已满。如果没有满,则将tail后移一位,将新元素放置在tail所在位置。出队时,也可以通过tail的位置判断队列是否为空。如果不空,则只需将head后移一位即可。 获取队头元素,判断队列不空,则只需返回head指向位置的元素即可。
但是!!想一下,通过出队操作将数据弹出队列后,head之前的空间还能够再次得到吗?不能。所以使用普通数组实现队列,就再也不能使用head之前的空间了,这会导致大量空间丢失。
所以,在这里我们使用环形队列!!
环形队列为空的时候,此时 head和tail是重合的。
环形队列为满的时候,此时head和tail 也是重合的。
如何解决这个问题?
环形队列如何区分空和满呢??方案:有两个。
1、不要把这个环形队列压榨的那么干净,故意浪费一个空间。即用head和 tail重合表示空队列,使用tail == head - 1表示满队列。
2、不浪费空间,然后专门搞一个size变量记录队列的元素个数.。size == 0就是空, size ==数组长度就是满。
package homework.stackAndqueue;
public class MyQueue {
private int[] data;
private int capacity = 100;
private int head = 0;
private int tail = 0;
private int size = 0;
public MyQueue(){
data = new int[capacity];
}
//入队列
private void realloc(){
capacity = capacity + 100;
int[] newData = new int[capacity];
int[] data = new int[0];
for(int i = 0; i < data.length; i++){
newData[i] = data[i];
}
}
public boolean offer(int val) {
if (size == data.length) {
realloc();
return false;
}
data[tail] = val;
tail++;
if (tail == data.length) {
tail = 0;
}
size++;
return true;
}
// 出队列
public Integer poll() {
if (size == 0) {
return null;
}
int ret = data[head];
head++;
if (head == data.length) {
head = 0;
}
size--;
return ret;
}
// 取队首元素
public Integer peek() {
if (size == 0) {
return null;
}
return data[head];
}
}
2、链接存储:使用尾插表示入队列,使用头删表示出队列,直接获取到头结点就是取队首元素。
package homework.stackAndqueue;
public class MyQueueWithNode {
class Node{
int val;
Node next;
public Node(int val){
this.val = val;
}
}
private Node head = null;
private Node tail = null;
//入队列
public boolean offer(int val){
Node newNode = new Node(val);
if(head == null){
head = newNode;
tail = newNode;
return true;
}
tail.next = newNode;
tail = tail.next;
return true;
}
//出队列
public Integer poll(){
if(head == null){
return null;
}
int ret = head.val;
if(head.next == null){
head = null;
return ret;
}
head = head.next;
return ret;
}
//取队首元素
public Integer peek(){
if(head == null){
return null;
}
return head.val;
}
}