Java双端队列

时间:2020-01-09 10:35:47  来源:igfitidea点击:

Java Deque接口java.util.Deque表示一个双头队列,表示一个队列,我们可以在该队列的两端添加和删除元素。名称Deque是Double Ended Queue的缩写。单词Deque的发音像纸牌的" deck"一样,是" deck"。

因为我们可以从Java Deque的两端入队和出队,所以可以将Deque用作队列和堆栈。 JavaDeque接口扩展了Java Queue接口。这意味着在使用Deque时可以使用所有Java Queue方法。 Deque接口没有扩展Java Stack接口,但是Deque接口定义了使我们能够执行通常在堆栈上执行的相同操作(push,peek,pop)的方法。

双端队列实现

由于JavaDeque是一个接口,因此我们需要实例化该接口的具体实现才能使用它。我们可以在Java Collections API中的以下Deque实现中进行选择:

  • java.util.LinkedList
  • java.util.ArrayDeque

LinkedList类是一个非常标准的Deque和Queue实现。它在内部使用链接列表来对队列或者双端队列进行建模。

JavaArrayDeque类将其元素内部存储在数组中。如果元素数超过数组中的空间,则会分配一个新的数组,并且所有元素都将移到该数组中。换句话说,即使将其元素存储在数组中," ArrayDeque"也会根据需要增长。

创建双端队列

在使用Java Deque之前,必须创建实现Deque接口的类之一的实例。这是通过创建LinkedList实例创建JavaDeque实例的示例:

Deque deque = new LinkedList();

这是通过创建ArrayDeque实例来创建JavaDeque的另一个示例:

Deque deque = new ArrayDeque();

通用双端队列

默认情况下,我们可以将任何Object放入JavaDeque中。但是,使用Java泛型可以限制我们可以插入到Deque中的对象的类型。这是一个例子:

Deque<MyObject> deque = new LinkedList<MyObject>();

现在,这个"双端队列"只能插入" MyObject"实例。然后,我们可以访问和迭代其元素,而无需强制转换它们。外观如下:

MyObject myObject = deque.remove();

for(MyObject anObject : deque){
   //do someting to anObject...
}

在声明Java Deque变量时始终指定通用类型被认为是一种好习惯。这样,编译器可以检查将什么类型插入到双端队列中,并且当我们再次将它们从双端队列中取出时,不必强制转换对象。另外,下一个阅读代码的人会更清楚此Deque应该包含哪种对象。

有关Java泛型的更多信息,请参见Java泛型教程。

将元素添加到双端队列

如本JavaDeque教程的开头所述,我们可以将元素添加到Deque的开头和结尾。 JavaDeque接口包含以下用于向其添加元素的方法:

  • add()
  • addLast()
  • addFirst()
  • offer()
  • offerFirst()
  • offerLast()

这些方法将在以下各节中说明。

add()

使用add()方法将元素添加到Deque的开头。这是在Java Deque的末尾添加元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("element 1");

如果不能将元素插入Deque中,则add()方法将引发异常。这与offer()方法不同,后者无法插入元素时将返回false。

实际上,add()方法是从Queue接口继承的。

addLast()

addLast()方法还将元素添加到Java Deque的末尾。这是Deque接口,等效于从Queue接口继承的add()方法。这是一个使用addLast()方法向Java Deque实例添加元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.addLast("element 1");

如果不能将元素插入Deque中,则addLast()方法将引发异常。这与offerLast()方法不同,如果无法将元素添加到双端队列,该方法将返回" false"。

addFirst()

要在Java Deque的开头(头)而不是Java的末尾添加元素,请调用addFirst()方法。这是在Java Deque的开头(头部)添加元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.addFirst("element 1");

如果不能将元素添加到Deque的开头,则addFirst()方法将引发异常。这与offerFirst()方法不同,后者无法在Deque的开头插入元素时返回false。

offer()

offer()方法会在Deque的末尾添加一个元素。如果添加元素成功,那么offer()方法将返回true。如果添加元素失败,例如如果双端队列已满,则" offer()"方法返回" false"。这与add()方法不同,后者会引发异常,因为在Deque末尾添加元素失败。这是一个使用offer()方法将元素添加到Java Deque末尾的示例:

Deque<String> deque = new ArrayDeque<>();

deque.offer("element 1");

offerLast()

offer()一样,offerLast()方法会在Deque的末尾添加一个元素。方法名称" offerLast()"只不过是关于将元素添加到双端队列的位置而已。如果添加元素成功,则offerLast()方法将返回true。如果添加元素失败,例如如果双端队列已满,则" offerLast()"方法返回" false"。这与addLast()方法不同,后者会引发异常,因为在Deque的末尾添加元素失败。这是一个如何使用offerLast()方法将元素添加到Java Deque末尾的示例:

Deque<String> deque = new ArrayDeque<>();

deque.offerLast("element 1");

offerFirst()

offerFirst()方法将一个元素添加到双端队列的开头(头)。如果添加元素成功,那么offerFirst()方法将返回true。如果添加元素失败,例如如果双端队列已满,则" offerFirst()"方法返回" false"。这与addFirst()方法不同,后者会引发异常,因为在Deque的开头添加了一个元素而失败。这是一个如何使用offerFirst()方法将元素添加到Java Deque开头的示例:

Deque<String> deque = new ArrayDeque<>();

deque.offerFirst("element 1");

push()

push()方法将一个元素添加到Java Deque方法的开头(头)。如果添加元素失败,例如,如果Deque已满,则push()方法将引发异常。这类似于addFirst()方法的工作方式。这是一个使用push()方法将元素添加到Java Deque开头的示例:

Deque<String> deque = new LinkedList<>();

deque.push("element 0");

查看Deque中的元素

我们可以查看Java Deque的第一个和最后一个元素。窥视元素意味着无需从Deque中移除元素即可获得对该元素的引用。我们可以使用以下方法查看Java Deque的第一个和最后一个元素:

  • peek()
  • peekFirst()
  • peekLast()
  • getFirst()
  • getLast()

以下各节将介绍这两种方法。

peek()

peek()方法从Java Deque的开头(头)返回第一个元素,而不删除它。如果双端队列为空,则peek()返回null。这是一个使用peek()方法窥视JavaDeque的第一个元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");
deque.add("last element");

String firstElement = deque.peek();

运行此代码后," firstElement"将指向添加到Deque中的第一个String元素:" first element"。

peekFirst()

peekFirst()方法从Java Deque的开头(头)返回第一个元素,而不删除它。如果双端队列为空,则peekFirst()返回null。这与peek()的工作方式类似,但是方法名称peekFirst()稍微说明了我们在Deque的哪一端看。这是一个使用peekFirst()方法来窥视JavaDeque的第一个元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");
deque.add("last element");

String firstElement = deque.peekFirst();

运行此代码后," firstElement"将指向添加到Deque中的第一个String元素:" first element"。

peekLast()

要查看Java Deque的最后一个元素,可以使用peekLast()方法。如果双端队列为空,则peekLast()将返回null。这是一个使用peekLast()方法来窥视JavaDeque的最后一个元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");
deque.add("last element");

String lastElement = deque.peekLast();

运行此Java示例之后,变量lastElement将指向字符串last element,因为该字符串是添加到Deque中的最后一个元素。

getFirst()

" getFirst()"方法从Java Deque的开头(头部)返回第一个元素,而不会将其删除。如果双端队列为空,则getFirst()会引发异常。这是使用getFirst()方法窥视Java Deque的第一个元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");
deque.add("last element");

String firstElement = deque.getFirst();

运行此代码后," firstElement"将指向添加到Deque中的第一个String元素:" first element"。

getLast()

要查看Java Deque的最后一个元素,可以使用getLast()方法。如果双端队列为空,则getLast()将返回null。这是使用getLast()方法窥视Java Deque的最后一个元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");
deque.add("last element");

String lastElement = deque.getLast();

运行此Java示例之后,变量lastElement将指向字符串last element,因为该字符串是添加到Deque中的最后一个元素。

从双端队列中删除元素

要从Java Deque中删除元素,可以使用以下方法之一:

  • remove()
  • removeFirst()
  • removeLast()
  • poll()
  • pollFirst()
  • pollLast()

以下各节将说明每种方法。

remove()

remove()方法删除JavaDeque的第一个元素。这是"双端队列"开头的元素。实际上,remove()方法是从Queue接口继承的。 remove()方法返回从'Deque'中删除的元素。这是一个使用remove()方法删除Java'Deque'第一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");

String removedElement = deque.remove();

如果双端队列为空,则remove()将引发异常。这与poll()不同,后者在Deque为空时返回null。

removeFirst()

removeFirst()方法还从'Deque'中删除第一个元素,即Deque头部的元素。这是一个使用removeFirst()方法删除JavaDeque的第一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");

String removedElement = deque.removeFirst();

如果双端队列为空,则removeFirst()将引发异常。这与pollFirst()不同,后者在Deque为空时返回null。

removeLast()

removeLast()方法将删除'Deque'的最后一个元素,这意味着该元素位于'Deque'尾部。这是一个使用removeLast()方法删除JavaDeque的最后一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");
deque.add("element 1");
deque.add("element 2");

String removedElement = deque.removeLast();

运行该Java示例后,removedElement变量将指向String对象element 2,因为当调用removeLast()时,该元素是Deque的最后一个元素。

如果双端队列为空,则removeLast()将引发异常。这与pollLast()不同,后者在Deque为空时返回null。

poll()

poll()方法从Deque的开头删除一个元素。如果双端队列为空,则poll()返回null。这与remove()不同,后者在Deque为空时抛出异常。这是一个使用poll()方法从Java Deque中删除第一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");
deque.add("element 1");
deque.add("element 2");

String removedElement = deque.poll();

pollFirst()

pollFirst()方法从Deque的开头删除一个元素,就像poll()一样。方法名称pollFirst()只是关于该方法从何处删除元素的说法。如果双端队列为空,则pollFirst()返回null。这与removeFirst()不同,后者在Deque为空时抛出异常。这是一个使用pollFirst()方法从Java Deque中删除第一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");
deque.add("element 1");
deque.add("element 2");

String removedElement = deque.pollFirst();

pollLast()

pollLast()方法从双端队列的末尾删除一个元素。如果双端队列为空,则pollLast()返回null。这与removeLast()不同,后者在Deque为空时抛出异常。这是一个使用pollLast()方法从Java Deque中删除最后一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");
deque.add("element 1");
deque.add("element 2");

String removedElement = deque.pollLast();

pop()

pop()方法从Java Deque的开头(头部)删除元素。如果删除元素失败,例如如果Deque为空,则pop()方法将引发异常。这类似于removeFirst()方法的工作方式。这是一个使用pop()方法从Java Deque中删除第一个元素的示例:

Deque<String> deque = new LinkedList<>();

deque.push("element 0");

String removedElement = deque.pop();

检查双端队列是否包含元素

我们可以使用Java Dequecontains()方法检查Deque是否包含给定元素。如果Deque包含元素,则" contains()"方法将返回" true",否则返回" false"。这是一个使用contains()方法检查Java Deque是否包含特定元素的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");

boolean containsElement1 = deque.contains("first element");
boolean containsElement2 = deque.contains("second element");

运行此代码后,因为Deque包含Java字符串"第一个元素",所以" containsElement1"变量将具有值" true",而由于Deque不包含Java字符串" containsElement2"将包含值" false",第二要素"。

双端队列大小

Java Deque的size()方法返回调用该方法时存储在Java Deque中的元素数。这是一个使用其Deque()方法获取Java Deque中元素数量的示例:

Deque<String> deque = new ArrayDeque<>();

deque.add("first element");
deque.add("second element");

int size = deque.size();

运行此代码后,size变量将包含值'2',因为Deque在调用size()时包含2个元素。

重复双端队列元素

我们还可以迭代Java Deque的所有元素,而不仅仅是一次处理一个元素。我们可以通过两种方式迭代Deque的元素:

  • 使用迭代器
  • 使用for-each循环。

这两个选项将在以下各节中进行说明。注意,在迭代过程中获得元素的顺序取决于具体的Deque实现。但是,不管实现如何,迭代元素的方法都是相同的。

通过迭代器迭代元素

迭代"双端队列"的元素的第一种方法是从"双端队列"中获取一个迭代器,并通过该迭代器来迭代元素。这是一个通过Iterator迭代Java Deque元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");
deque.add("element 1");
deque.add("element 2");

Iterator<String> iterator = deque.iterator();
while(iterator.hasNext(){
  String element = iterator.next();
}

通过For-Each循环迭代元素

迭代Deque元素的第二种方法是在Java中使用for-each循环。这是一个通过for-each循环迭代JavaDeque的元素的示例:

Deque<String> deque = new LinkedList<>();

deque.add("element 0");
deque.add("element 1");
deque.add("element 2");

for(String element : deque) {
    System.out.println(element);
}

JavaDoc中的更多详细信息

使用Deque可以做更多的事情,但是我们必须查看JavaDoc以获得更多详细信息。本文重点介绍两个最常见的操作:添加/删除元素和迭代元素。