五、集合——5-Queue集合
5-Queue集合
1.概述
Queue用于模拟队列这种数据结构,队列通常是指先进先出的容器。队列的头部保存着在容器中存在时间最长的元素,在尾部保存在容器中存放时间最短的元素;新元素插入到队列的尾部,访问元素操作会返回队列头部的元素。通常情况下,队列不允许随机访问队列中的元素。
Queue接口中定义的方法:
(1)void add(Object o):在队列尾部添加新的元素;
(2)Object element():获取队列头部的元素,但不删除该元素;
(3)boolean offer(Object o):将指定元素加入到队列尾部。当使用有容量限制的队列时,此方法比add()方法好用;
(4)Object peek():获取队列头部的元素,但不是删除该元素。如果队列为空则返回null;
(5)Object poll():获取队列头部的元素,同时删除该元素。当此队列为空时,返回null。
2.PriorityQueue实现类
(1)PriorityQueue是Queue接口的实现类,它并不是一个完全的队列集合,因为在存储过程中,PriorityQueue会根据元素的大小进行排序,类似于TreeSet;
(2)当调用poll()方法或者peek()方法时,返回的元素并不是在容器中存放时间最久的元素,而是在此容器中最小的元素;
(3)PriorityQueue不允许插入null元素,还需要对元素进行排序,它的排序方式有两种:
1)自然排序:元素对应的类实现Comparable接口;(类似于TreeSet)
2)定制排序:关联Comparator对象;(类似于TreeSet)
(4)PriorityQueue的简单使用:
import java.util.PriorityQueue; public class PriorityQueueTest { public static void main(String[] args) { //创建一个PriorityQueue队列 PriorityQueue pq = new PriorityQueue(); //依次向pq中添加元素 pq.offer(1); pq.offer(8); pq.offer(2); pq.offer(5); //在输出时,发现排序也并非按照升序的方式排列 //这是由于PriorityQueue重写的toString()方法影响所致 System.out.println(pq); //循环使用poll()取出元素并删除元素 int pqSize = pq.size(); //这里注意一下,如果在for条件中使用pq.size()这个值是在改变的 for(int i=0;i<pqSize;i++){ System.out.println(pq.poll()); } System.out.println(pq); } }
3.Deque接口和ArrayDeque实现类
Deque接口:
(1)Deque接口是Queue接口的子接口,它代表一个双端队列,在Deque接口中定义了许多的方法,这些方法用来从两端操作队列中的元素:
import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; //Deque接口中定义的方法 public class DequeTest { public static void main(String[] args) { Deque dq = new ArrayDeque(); //============================================= //将指定元素插入到该双端队列的开头 //也可以使用offerFirst()方法,此方法有返回值 dq.addFirst(1); dq.addFirst(2); dq.addFirst(3); dq.addFirst(4); dq.addFirst(5); dq.addFirst(6); System.out.println(dq); //输出6 5 4 3 2 1 //将指定元素插入到该双端队列的结尾 //也可以使用offerLast()方法,此方法有返回值 dq.addLast(7); dq.addLast(8); dq.addLast(9); dq.addLast(10); dq.addLast(11); System.out.println(dq); //输出6 5 4 3 2 1 7 8 9 10 11 //============================================= //获取该双端队列的迭代器Iterator,该Iterator逆向迭代此双端队列 Iterator it = dq.descendingIterator(); while(it.hasNext()){ System.out.println(it.next()); } //============================================= //获取但不删除该队列的第一个元素 //也可以使用peekFirst()方法,如果该队列为空则返回null System.out.println(dq.getFirst()); //获取但不删除该队列的最后一个元素 //也可以使用peekLast()方法,如果该队列为空则返回null System.out.println(dq.getLast()); //============================================= //获取并删除该双端队列的第一个元素 dq.pollFirst(); System.out.println(dq); //获取并删除该双端队列的最后一个元素 dq.pollLast(); System.out.println(dq); //============================================= //pop出该双端队列所表示栈栈顶的元素 System.out.println(dq.pop()); System.out.println(dq); //把一个元素push到该双端队列的栈顶 dq.push(1); System.out.println(dq); //============================================= //获取并删除该双端队列的第一个元素 System.out.println(dq.removeFirst()); //获取并删除该双端队列的第一次出现的元素 System.out.println(dq.removeFirstOccurrence(1)); System.out.println(dq); //获取该双端队列的最后一个元素 System.out.println(dq.removeLast()); System.out.println(dq); //获取并删除该双端队列的最后一次出现的元素 System.out.println(dq.removeLastOccurrence(2)); System.out.println(dq); } }
ArrayDeque实现类:
(1)ArrayDeque是Deque接口的实现类,它是一个基于数组实现的双端队列,Deque底层数组的默认长度为16;
(2)ArrayDeque的使用:
1)ArrayDeque作为栈使用:
import java.util.ArrayDeque; public class ArrayDequeStack { public static void main(String[] args) { ArrayDeque stack = new ArrayDeque(); //依次将1 2 3 push入栈中 stack.push(1); stack.push(2); stack.push(3); System.out.println(stack); //访问栈顶的元素,并不删除 System.out.println(stack.peek()); //pop出栈顶的元素 stack.pop(); System.out.println(stack); } }
2)ArrayDeque作为队列使用:
import java.util.ArrayDeque; public class ArrayDequeQueue { public static void main(String[] args) { ArrayDeque queue = new ArrayDeque(); //依次将三个元素加入队列 queue.offer(1); queue.offer(2); queue.offer(3); System.out.println(queue); //访问队列头部的元素,并不poll出队列 System.out.println(queue.peek()); //poll出队列的第一个元素 System.out.println(queue.poll()); System.out.println(queue); } }
4.LinkedList实现类
(1)LinkedList实现类实现了List接口,同时也实现了Deque接口,所以它可以根据索引随机访问集合中的元素,也可以作为一个双端队列使用(即可以当成队列使用,也可以当做栈来使用);
(2)LinkedList同ArrayList、ArrayDeque相比较他们实现的方式完全不同,ArrayDeque、ArrayList是以数组的形式来保存元素的,在随机访问集合元素时有较好的性能;而LinkedList是使用链表的形式来保存元素的,因此随机访问集合元素的性能较差,但是在插入、删除元素时有较好的性能;
(3)LinkedList的简单使用:
import java.util.LinkedList; public class LinkedListTest { public static void main(String[] args) { LinkedList list = new LinkedList(); //将元素加入队列尾部 list.offer(1); //将元素加入栈的顶部 list.push(2); System.out.println(list); //将元素加入队列的头部,相当于栈的顶部 list.offerFirst(3); //按照索引遍历集合 for(int i = 0;i<list.size();i++){ System.out.println(list.get(i)); } //访问并不删除栈顶的元素 System.out.println(list.peekFirst()); //访问并不删除队列的最后一个元素 System.out.println(list.peekLast()); //将栈顶元素pop出栈 list.pop(); System.out.println(list); //访问并删除队列最后一个元素 System.out.println(list.pollLast()); System.out.println(list); } }
5.性能分析
(1)ArrayList和LinkedList:
随机访问集合元素时,使用ArrayList;对集合使用添加、删除操作时,使用LinkedList;
(2)有关List集合使用建议:
1)遍历List集合元素时,对于ArrayList、Vector集合来说,使用随机访问的方式(get()方法)来遍历集合;对于LinkedList集合,应该使用迭代器(Iterator)来遍历集合;
2)经常需要进行插入、删除操作的集合选用LinkedList集合;
3)多个线程访问List集合时,使用Collections工具类将其包装成线程安全的集合。