对于大多数人来说,“队列”这个词在脑海中几乎没有什么愉快的联想。但今天我们谈论的是不同的队列——Java 队列。在 Java 中,队列是继承Queue接口的任何东西,而 Queue 接口又扩展了Collection接口。这意味着队列可以像集合一样对待。
Java 中的队列支持两种操作原则:FIFO和LIFO。
FIFO (先进先出)原则支配着常规队列——第一个加入队列的元素最先离开。
LIFO (后进先出)原则描述了堆栈的行为——最后添加到队列的元素最先离开。例如,这就是处理一副纸牌的方式:您一次从最上面的一张纸牌中取出纸牌,直到到达纸牌的底部。
Java 中的队列层次结构如下所示:
这里可以看到Queue有 3 个实现类:LinkedList、ArrayDeque和PriorityQueue。LinkedList和ArrayDeque直接继承的不是Queue,而是Deque。
Deque是在 Java 6 中添加的接口。它包括几个对队列有用的方法,并允许队列充当双端(或双向)队列。这意味着它可以是FIFO和LIFO。
Deque接口的两个后代之一是ArrayDeque。它支持双端队列,允许您从两端插入和删除元素。它也是一个自动增长大小的动态数组。
还有一个PriorityQueue类,它是Queue的直接后代:它的行为不同于实现Deque 的类。
PriorityQueue是一个优先级队列,默认情况下根据元素的自然顺序组织元素。这里的排序使用Comparable和Comparator接口。原理与TreeSet或TreeMap相同— 使用Comparable接口并具有自己的排序顺序的类。
PriorityQueue<String> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(String::length));
priorityQueue.add("Andrew");
priorityQueue.add("John");
priorityQueue.add("Rob");
while (!priorityQueue.isEmpty()) {
System.out.println(priorityQueue.remove());
}
如果您运行此示例,您将在控制台中看到以下内容:
·约翰·
安德鲁
由于我们使用的是队列而不是常规集合,因此我们需要从列表中删除元素。为此,我们使用以下构造:
while (!priorityQueue.isEmpty()) {
System.out.println(priorityQueue.remove());
}
Deque接口继承了Queue方法并添加了几个它自己有趣的方法:
void addFirst(E obj) | 将obj元素添加到队列的前面 |
void addLast(E obj) | 将obj元素添加到队列的末尾 |
E getFirst() | 返回队列中的第一个元素 |
E getLast() | 返回队列中的最后一个元素 |
boolean offerFirst(E obj) | 将obj元素添加到队列的前面,如果添加了元素则返回true 。否则,返回false。 |
布尔报价最后(E obj) | 将obj元素添加到队列的末尾,如果添加了元素则返回true 。否则,返回false。 |
E pop() | 从队列中获取第一个元素并将其移除 |
void push(E obj) | 将obj元素添加到队列的前面 |
E peekFirst() | 返回(但不移除)队列中的第一个元素 |
E peekLast() | 返回(但不移除)队列中的最后一个元素 |
E pollFirst() | 返回并移除队列中的第一个元素。如果没有元素,则返回null 。 |
E pollLast() | 返回并移除队列中的最后一个元素。如果没有元素,则返回null 。 |
E 移除最后一个() | 返回并移除队列的第一个元素。如果没有元素则抛出异常。 |
E removeFirst() | 返回并移除队列的最后一个元素。如果没有元素则抛出异常。 |
布尔 removeFirstOccurrence(对象 obj) | 从队列中移除第一次出现的obj |
布尔 removeLastOccurrence(对象 obj) | 从队列中移除最后一次出现的obj |
现在让我们在实践中看看其中的一些方法。
首先,让我们向队列中添加一个元素:
Deque<String> deque = new ArrayDeque<>();
deque.add("Apple"); // Adds "Apple" to the end of the queue
deque.addFirst("Orange"); // Adds "Orange" to the front of the queue
deque.addLast("Pineapple"); // Adds "Pineapple" to the end of the queue
System.out.println(deque);
现在让我们从队列中获取值:
Deque<String> deque = new ArrayDeque<>();
deque.add("Apple");
deque.addFirst("Orange");
deque.addLast("Pineapple");
System.out.println("The first element is: "+ deque.getFirst());
System.out.println("The last element is: " + deque.getLast());
}
此代码显示队列的第一个和最后一个元素。
最后一个元素是:Pineapple
Deque<String> deque = new ArrayDeque<>();
deque.add("Apple");
deque.addFirst("Orange");
deque.addLast("Pineapple");
deque.add("Lemon");
System.out.println(deque.pop()); // Get and remove the first element of the queue
System.out.println(deque.poll()); // Get and remove the first element of the queue
System.out.println(deque);
运行这段代码,我们得到:
苹果
[菠萝、柠檬]
pop()和poll()之间的区别在于,如果列表为空列表,pop()将抛出NoSuchElementException ,但poll()将返回null。
现在我们将考虑pollFirst()和pollLast()方法。
Deque<String> deque = new ArrayDeque<>();
deque.add("Apple");
deque.addFirst("Orange");
deque.addLast("Pineapple");
deque.add("Lemon");
System.out.println(deque.pollFirst()); // Get and remove the first element of the queue
System.out.println(deque.pollLast()); // Get and remove the last element of the queue.
System.out.println(deque);
柠檬
[苹果、菠萝]
这两种方法都返回并从队列中删除一个值。
下面是使用peekFirst()和peekLast()方法的示例:
Deque<String> friends = new ArrayDeque<>();
friends.add("John");
friends.add("Rob");
friends.add("Greg");
friends.add("Max");
friends.add("Oliver");
System.out.println("The first element is: " + friends.peekFirst());
System.out.println("The last element is: " + friends.peekLast());
System.out.println(friends);
最后一个元素是:Oliver
[John, Rob, Greg, Max, Oliver]
这两种方法都返回队列中的第一个/最后一个元素,并且不删除它们。如果队列为空,则返回null 。
做得好!今天我们学习了如何在 Java 中使用队列。现在您知道如何在实践中使用它们了。
GO TO FULL VERSION