一.概述
1.队列(queue)是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
2.队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
二.队列的分类
1.单向队列:只能在一端插入数据,另一端删除数据。可以使用数组和链表两种方式来实现,遵循先入先出(FIFO)的规则,即先进入的数据先出。单向队列属于有序列表。
2.双向队列:每一端都可以进行插入数据和删除数据操作。
3.优先级队列:优先级队列是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。
三.三种队列的Java实现
1.单向队列
(1)示意图
(2)代码实现
public class Queue {
private Object[] queArray;
//队列总大小
private int maxSize;
//队头指针
private int front;
//队尾指针
private int rear;
//队列中元素的实际数目
private int count;
public Queue(int s){
maxSize = s;
queArray = new Object[maxSize];
front = 0;
rear = -1;
count = 0;
}
//入队
public void insert(int value){
if(isFull()){
System.out.println("该队列已满,无法入队");
}else{
//队尾指针指向队头
if(rear == maxSize -1){
rear = -1;
}
//队尾指针加1,然后在队尾指针处插入新的数据
queArray[++rear] = value;
count++;
}
}
//移除数据
public Object remove(){
Object removeValue = null ;
if(!isEmpty()){
removeValue = queArray[front];
queArray[front] = null;
front++;
if(front == maxSize){
front = 0;
}
count--;
return removeValue;
}
return removeValue;
}
//查看队头
public Object peekFront(){
return queArray[front];
}
//判断队列是否满了
public boolean isFull(){
return (count == maxSize);
}
//判断队列是否为空
public boolean isEmpty(){
return (count ==0);
}
//返回队列的大小
public int getSize(){
return count;
}
}
2.双向队列
(1)代码实现
3.优先级队列
(1)代码实现
使用数组来实现优先级队列
public class PriorityQueue{
private int maxSize;
private int[] priQueArray;
private int count;
public PriorityQueue(int s){
maxSize = s;
priQueArray = new int[maxSize];
count = 0;
}
//插入数据
public void insert(int value){
int i;
if(count == 0){
priQueArray[count++] = value;
}else{
i = count -1;
//插入排序,按照从大到小的顺序排列,越小的越在队列的顶端
while(i >=0 && value > priQueArray[i]){
priQueArray[i+1] = priQueArray[i];
i--;
}
priQueArray[i+1] = value;
count++;
}
}
public int remove(){
int k = count -1;
int value = priQueArray[k];
priQueArray[k] = -1;//-1表示这个位置的数据被移除了
count--;
return value;
}
//查看优先级最高的元素
public int peekMin(){
return priQueArray[count -1];
}
//判断队列是否为空
public boolean isEmpty(){
return (count == 0);
}
//判断队列是否满了
public boolean isFull(){
return (count == maxSize);
}
}
四.Java队列一些常用方法的区别
1.offer(),add() 区别:
一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
这时新的 offer()方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
2.poll(),remove() 区别:
remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似, 但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。
3.peek(),element()区别:
element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。
五.队列的应用场景
一般情况下,如果是对一些及时消息的处理,并且处理时间很短的情况下是不需要队列的,直接阻塞式的方法调用就可以了。但是如果在消息处理的时候特别费时间,这个时候如果有新消息来了,就只能处于阻塞状态,造成用户等待。这个时候便需要引入队列了。当接收到消息后,先把消息房贷队列中,然后再用行的线程进行处理,这个时候就不会有消息阻塞了。队列先入先出的特点,使得其应用非常广泛,比如队列作为“缓冲区”,可以解决计算机和外设速度不匹配的问题,FIFO的特点保证了数据传输的顺序。