一. 概述
Queue一种队列结构集合,用来存储将要进行处理的元素.通常以FIFO的方式排序元素,但这并不是必须的.
比如优先度队列就是一个例外,它是以元素的值来排序.
但无论怎样,每个Queue的实现都必须指定它的排序属性.Queue通常不定义元素的equal和hashCode方法.
队列(queue) 是一种先进先出的数据结构。元素被追加到队列末尾,然后从队列头删。
在优先队列( priority queue) 中,元素被赋予优先级。当访问元素时,拥有最高优先级的元素首先被删除。
Queue 接口继承自java. util .Collection
队列有两种实现方式:一种是使用循环数组;另一种是使用链表。如果需要一个循环数组队列,使用ArrayDeque类;如果需要一个链表队列,就使用LinkedList,这个类实现了Queue接口。
二. 主要方法
每个Queue方法都存在两种形式
(1)操作失败则抛出异常
(2)操作失败返回一个特定值,通常是null或者是false
操作类型 | 抛出异常 | 返回特定值 |
---|---|---|
Insert | add(e) | offer(e) |
Remove | remove() | poll() |
Examine | element() | peek() |
Queue的实现可能会限制集合存储的元素数,这种队列被称为有界队列。
对于有界队列当调用add方法时,如果元素数超出其容量限制,就会抛出 IllegalStateException
异常,.offer
方法就是专门为有界队列设计的,和add不同的是当插入元素失败的的时候,它返回false而不是抛出异常.
Remove和poll方法都是从队列头部弹出元素。具体是那个元素被弹出,这要看队列的排序策略。
remove和poll仅当是空集合的时候才有区别,remove会抛出NoSuchElementException,而poll返回null值。
Element和peek方法都是返回队列的头部元素,但并不会从队列中将其删除。
同remove和poll一样仅当是空集合时两者才有差别,element抛出NoSuchElementException而peek返回null值。
Queue的实现通常不允许插入null值,除了LinkedList这个例外,出于历史原因它允许插入null值,但是必须十分注意的是null也是poll和peek方法返回的特别值。
三. 实现
Queue的实现可以划分为通用实现
和并发实现
通用实现主要有两个,一个是LinkedList
,一个是PriorityQueue
.
LinkedList
在List总我们已经说过,它继承自Queue接口,提供FIFO的队列操作形式.
PriorityQueue
是一个基于栈结构的优先度队列,它可以根据元素的自然排序或者给定的排序器进行排序.
在java.util.concurrent
包中包含了一系列的同步Queue接口和实类。BlockingQueue
继承自Queue,它会在检索元素时等待队列是非空队列处于可用状态,并在存入一个元素后将状态更改为可用状态,下面是它的实现类。
-
LinkedeBlockingQueue
—基于链接节点的可选有界FIFO方式阻塞式队列 -
ArrayBlockingQueue
—基于数组的有界FIFO方式的阻塞式队列 -
PriorityBlockingQueue
—基于栈结构无界阻塞式队列 -
DelayQueue
—基于栈结构的时间调度队列 -
SychronousQueue
—通过使用BlockingQueue接口的简单对接机制的队列
在JDK7中 ,TransferQueue是一个特殊额BlockingQueue,它向队列添加一个元素后,可以选择处于等待(阻塞)状态,以让另一个线程检索元素,TransferQueue只有一个实现类 -
LinkedTransferQueue
—基于链接节点的无界TransferQueue
四、LinkedList
LinkedList 实现了:List
、Deque
(双向链表结构)、Queue
(队列接口)。
Queue是在两端出入的List,所以也可以用数组或链表来实现。
队列:先进先出FIFO
offer
在最后添加元素
poll
取出第一个元素
peek
查看第一个元素
LinkedList:以双向链表实现的LinkedList既是List,也是Queue。它是唯一一个允许放入null的Queue。
Queue<Hero> q= new LinkedList<Hero>();
还有很多Quene,比如ArrayDeque
、PriorityQueue
。。。
方法:addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast()
LinkedList <xxx> ll = new LinkedList<xxx>();
ll.addFirst("q0"); //头部加入
ll.addLast("q1"); // 尾部加入
System.out.println(ll.getFirst()); //查看最前面的对象
System.out.println(ll.getLast()); //查看最后面的对象
System.out.println(ll.removeFirst()); // 从该线性表中返回并删除第一个对象
System.out.println(ll.removeLast()); // 从该线性表中返回并删除最后一个对象
System.out.println(ll); // 取出会导致对象被删除
特点
以双向链表
实现。链表无容量限制,但双向链表本身使用了更多空间,也需要额外的链表指针操作。
使用方法 list.get(i)
或者 list.set(15,"Lindon")
要悲剧的遍历链接,直到指针移到相应位置(如果 i 大于数组的一半,会从末尾开始)。不要使用get来遍历线性表中的所有元素,应该使用迭代器!!
for(listElementType s :List){ //foreach 循环隐式地使用了迭代器
process s;
}
插入、删除元素时修改前后节点的指针即可,但还是要遍历部分链表的指针才能移动到下标所指的位置,只有在链表两头的操作–add(), addFirst(),removeLast()或用iterator()上的remove()能省掉指针的移动。
ArrayList 和 LinkedList 的区别
ArrayList
- 插入/删除数据速度慢。因为要把插入点后所有对象移位。
- 顺序结构,可直接定位到某个位置的对象,定位速度快。
LinkedList
- 插入,删除数据快。只要断开插入点的连接,重新连接到别的块就OK。
- 链表结构,不可以直接定位到某个位置的对象,必须根据链表的方向一个一个找,定位速度慢。
public class TestCollection {
public static void main(String[] args) {
List<Integer> l1 = new ArrayList<>();
List<Integer> l2 = new LinkedList<>();
insertFirst(l1,"ArrayList");
insertFirst(l2,"LinkedList");
}
private static void insertFirst(List<Integer> l, String type) {
int total = 1000 * 100;
final int number = 5;
long start = System.currentTimeMillis();
for (int i = 0; i < total; i++) {
l.add(0, number);
}
long end = System.currentTimeMillis();
System.out.printf("在%s 最前面插入%d条数据,总共耗时 %d 毫秒 %n", type, total, end - start);
}
}
在ArrayList 最前面插入100000条数据,总共耗时 1006 毫秒
在LinkedList 最前面插入100000条数据,总共耗时 4 毫秒
练习
练习-使用LinkedList实现Stack栈
与FIFO(先入先出的)队列类似的一种数据结构是FILO先入后出栈Stack
根据接口Stack :
实现类:MyStack
public class MyStack implements Stack
并向这个栈中,压入5个英雄,接着弹出5个英雄
package collection;
import charactor.Hero;
public interface Stack {
//把英雄推入到最后位置
public void push(Hero h);
//把最后一个英雄取出来
public Hero pull();
//查看最后一个英雄
public Hero peek();
}
package collection;
import java.util.LinkedList;
import java.util.List;
public class MyStack implements Stack{
LinkedList<Hero> heros = new LinkedList<>();
@Override
//把英雄推入到最后位置
public void push(Hero h) {
heros.addLast(h);
}
@Override
public Hero pull() {
// TODO Auto-generated method stub
Hero h = heros.removeLast();
return h;
}
@Override
public Hero peek() {
// TODO Auto-generated method stub
Hero h = heros.getLast();
return h;
}
}