Java Deque是一种结合了普通Queue和Stack的数据结构。您可以在 Deque 的头部和尾部添加和删除元素。在“传统”队列中,您将元素添加到行的尾部(在最后一个元素之后)并从队列的头部移除元素。这一原则称为先进先出 (FIFO),它的工作方式与现实生活中任何常见的客户排队一样。在 Java 中,队列是一个接口,是集合框架的一部分。 还有一个重要的数据结构称为 Stack,这是一个以完全相反的原则处理元素的列表,LIFO——后进先出。它类似于一堆盘子,只能在顶部添加或移除。
队列与双端队列
Deque 是一种奇怪的队列类型:您可以将新元素添加到行的尾部和头部。删除的情况相同:您可以从此结构中删除最后一个或第一个元素。因此,它似乎是 Stack 和 Queue 的混合体。 “Deque”这个名字的意思是“双端队列”。“Deque”的发音就像一副纸牌,你知道吗?它有点类似于一副真正的纸牌:你可以从这样一副纸牌的底部或顶部拿一张牌。想在某些线性结构的两侧添加或删除元素?使用双端队列。Java 8 或几乎任何其他版本都支持它。想象一下典型的乐高积木和由积木制成的单柱“塔”。您可以在塔的顶部或底部添加一块新砖。您也可以从两侧移除一块砖。这里有一个示例:我们将所有黄色积木添加到顶部,将所有红色积木添加到底部。我们将很快用 Java 代码演示这个例子。 因此,您可以从 Java Deque 的两端入队和出队,这意味着您可以将 Deque 用作队列和堆栈。阅读 Java 中的堆栈:Java Stack 101:深入研究堆栈类 阅读 Java 中的队列:Java 队列接口及其实现双端队列的特点
- Java 中的 Deque 是一个接口,它的实现提供了对可变大小数组的支持。所以你有一个数组不受限制的容量,你可以根据你的需要添加新的元素。
- Deque 不支持多个线程的当前访问
- 在没有外部同步的情况下,双端队列不是线程安全的。
- 数组双端队列中不允许有 Null 元素。
双端队列 Java 接口声明
public interface Deque<E> extends Queue<E>
Java 双端队列方法
java.util.Deque是一个扩展 Java 队列接口的接口,代表一个双端队列。因此,您可以在使用 Deque 时使用所有 Java Queue 方法。尽管 Deque 没有扩展 Stack 接口,但 Deque 接口定义了一些方法,使您能够执行典型的堆栈操作,例如push、peek和pop。- boolean add(element)添加一个元素到双端队列的尾部。成功时返回 true,如果当前没有可用空间则抛出 IllegalStateException。
- addFirst(element)将一个元素添加到 Deque 的头部。
- addLast(element)将一个元素添加到双端队列的尾部。
- offer(element)在尾部添加一个元素并返回一个布尔值来说明插入是否成功。
- offerFirst(element)向头部添加一个元素并返回一个布尔值来说明插入是否成功。
- offerLast(element)在尾部添加一个元素并返回一个布尔值来说明插入是否成功。
- iterator()返回双端队列的迭代器。
- descendingIterator()返回一个迭代器,该迭代器具有与此双端队列相反的顺序。
- push(element)向头部添加一个元素。
- pop(element)从头部移除一个元素并返回它。
- removeFirst()删除头部的元素。
- removeLast()删除尾部的元素。
- poll()检索并移除此双端队列所表示的队列的头部(换句话说,此双端队列的第一个元素),或者如果此双端队列为空,则返回 null。
- pollFirst()检索并删除此双端队列的第一个元素,如果此双端队列为空,则返回 null。
- pollLast()检索并删除此双端队列的最后一个元素,如果此双端队列为空,则返回 null。
- peek()检索但不移除此双端队列所代表的队列的头部(换句话说,此双端队列的第一个元素),或者如果此双端队列为空则返回 null。
- peekFirst()检索但不删除此双端队列的第一个元素,如果此双端队列为空,则返回 null。
- peekLast()检索但不删除此双端队列的最后一个元素,如果此双端队列为空,则返回 null。
第一元素(头) | 最后一个元素(尾巴) | |||
---|---|---|---|---|
手术 | 抛出异常 |
特别价值 | 抛出异常 | 特别价值 |
插入 | 添加第一(e)/推(e) | 报价第一(e) | 添加最后一个(e) | 最后报价() |
消除 | removeFirst()/弹出() | 轮询优先() | 移除最后一个() | 轮询最后() |
检查 | getFirst() | peekFirst()/偷看() | 获取最后一个() | peekLast() |
双端队列实现
Java Deque 是一个接口,在 Java Collections API 中有实现:- java.util.LinkedList //List和Deque的实现
- java.util.ArrayDeque //双端队列实现,Java库
ArrayDeque 类
ArrayDeque <E>类是一个通用的双向队列,继承了 AbstractCollection 类的功能并使用了 Deque 接口。ArrayDeque 提供了使用 deque 和 resizable-array 的便利。最初,数组的大小初始化为 16。它被实现为一个双向队列,它支持两个指针,即头和尾。它继承了AbstractCollection类并实现了Deque接口。关于 ArrayDeque 类的要点是:- 您可以从 ArrayDeque 的尾部和头部添加或删除元素
- 不允许空元素
- 在没有外部同步的情况下,ArrayDeque 不是线程安全的。
- ArrayDeque 没有容量限制。
ArrayDeque 类构造函数
- ArrayDeque()创建一个空队列。
- ArrayDeque(Collection <? extends E> collection)创建一个队列,里面装满了Collection集合元素。
- ArrayDeque(int capacity)创建一个初始容量为capacity的队列。如果不指定初始容量,则默认容量为 16。
Java 双端队列示例——ArrayDeque
还记得文章开头的乐高塔示例吗?让我们创建一个类来构建由乐高积木制成的单柱塔。积木可以是红色、黄色或蓝色。我们的塔楼规则:我们将红砖放在底部,将黄砖放在顶部。大 Java 双端队列示例
//enum with colors
public enum Color {
RED, YELLOW, BLUE;
}
//class for the standard Lego Brick. You can connect or disconnect the Brick, it has color
public class LegoBrick {
Color color;
boolean isConnected;
public void connect() {
System.out.println("This brick is connected");
this.isConnected = true;
}
public void disconnect() {
System.out.println("Disconnected");
isConnected = false;
}
public LegoBrick(Color color, boolean isConnected) {
this.color = color;
this.isConnected = isConnected;
}
public Color getColor() {
return color;
}
public boolean isConnected() {
return isConnected;
}
@Override
public String toString() {
return "LegoBrick{" +
"color=" + color +
", isConnected=" + isConnected +
'}';
}
}
这是我们的 Tower 类。我们启动一座塔。启动塔取决于红色和黄色的数量。我们可以在塔上添加砖块或将其移除。如果是黄色,我们将砖块添加到顶部,如果是红色,则将其添加到底部。
import java.util.ArrayDeque;
public class LegoTower {
ArrayDeque<LegoBrick> myTower;
int quantityOfReds;
int quantityOfYellows;
public void addBrickToTower(LegoBrick newLegoBrick) {
if (newLegoBrick.getColor() == Color.YELLOW) {
this.myTower.offerLast(newLegoBrick);
quantityOfYellows++;
}
//we can use addFirst(e)/push(e) instead of offerFirst here
if (newLegoBrick.getColor() == Color.RED) {
myTower.offerFirst(newLegoBrick);
quantityOfReds++;
}
}
public void removeBrickFromTower (LegoBrick legoBrick) {
if (legoBrick.getColor() == Color.YELLOW) {
this.myTower.removeLast();
quantityOfYellows--;
}
if (legoBrick.getColor() == Color.RED) {
myTower.removeFirst();
quantityOfReds--;
}
legoBrick.isConnected = false;
}
public LegoTower(int quantityOfReds, int quantityOfYellows) {
myTower = new ArrayDeque<>();
this.quantityOfReds = quantityOfReds;
this.quantityOfYellows = quantityOfYellows;
for (int i = 0; i < quantityOfReds; i++) {
LegoBrick redLegoBrick = new LegoBrick(Color.RED, false);
myTower.addFirst(redLegoBrick);
redLegoBrick.isConnected = true;
}
for (int i = 0; i < quantityOfYellows; i++) {
LegoBrick yellowLegoBrick = new LegoBrick(Color.YELLOW, false);
myTower.addLast(yellowLegoBrick);
yellowLegoBrick.isConnected = true;
}
}
public void setMyTower(ArrayDeque<legobrick> myTower) {
this.myTower = myTower;
}
public void setQuantityOfReds(int quantityOfReds) {
this.quantityOfReds = quantityOfReds;
}
public void setQuantityOfYellows(int quantityOfYellows) {
this.quantityOfYellows = quantityOfYellows;
}
@Override
public String toString() {
return "LegoTower{" +
"myTower=" + myTower +
", quantityOfReds=" + quantityOfReds +
", quantityOfYellows=" + quantityOfYellows +
'}';
}
public void drawTower() {
for (LegoBrick i : myTower) {
System.out.println(i.color);
}
}
}
public class Main {
public static void main(String[] args) {
LegoBrick legoBrick1 = new LegoBrick(Color.YELLOW, false);
legoBrick1.connect();
System.out.println(legoBrick1.toString());
legoBrick1.disconnect();
System.out.println(legoBrick1.toString());
LegoBrick legoBrick2 = new LegoBrick(Color.YELLOW, false);
LegoBrick legoBrick3 = new LegoBrick(Color.RED, false);
LegoBrick legoBrick4 = new LegoBrick(Color.RED, false);
LegoBrick legoBrick5 = new LegoBrick(Color.YELLOW, false);
LegoTower legoTower = new LegoTower(2, 5);
System.out.println("my Initiated Lego Tower: ");
legoTower.drawTower();
legoTower.addBrickToTower(legoBrick1);
legoTower.addBrickToTower(legoBrick2);
legoTower.addBrickToTower(legoBrick3);
legoTower.addBrickToTower(legoBrick4);
legoTower.addBrickToTower(legoBrick5);
System.out.println("My LegoTower after adding some elements: ");
legoTower.drawTower();
legoTower.removeBrickFromTower(legoBrick1);
legoTower.removeBrickFromTower(legoBrick3);
System.out.println("We removed one red and one yellow brick:");
legoTower.drawTower();
}
}
运行这个程序的结果:
my Initiated LegoTower:
RED
RED
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
My LegoTower after adding some elements:
RED
RED
RED
RED
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
We removed one red and one yellow brick:
RED
RED
RED
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
YELLOW
Process finished with exit code 0
等等,什么??为什么红色在上面?不,他们没有。他们只是从第一个(底部)到最后一个(顶部)打印到控制台。所以如果你想看到像上面图片中的积木一样的东西,你可以改变 LegoTower 类的 drawTower 方法。这是一项非常容易的任务!
链表
List 接口保持添加项目的顺序,并允许通过索引访问项目。Deque 是一个双向队列,它支持从两侧添加和删除元素。 LinkedList 主要被称为 List 实现,但该类也实现了 Deque,它允许我们创建一个由包括 null 在内的任何对象组成的双向队列。LinkedList 是元素的集合。我们可以在类的代码源中看到,这次注意字段:这里我们添加一个例子,但是如果你想了解更多关于LinkedList的知识,欢迎阅读这篇CodeGym文章。Java中的链表实现,添加和删除元素。例子
让我们在实践中尝试这些操作。首先,Java LinkedList 实现:创建一个字符串的 LinkedList,添加 3 个元素。然后去掉一个,再在中间加一个。
public class MyLinkedTest {
public static void main(String[] args) {
String h1 = "my";
String h2 = "favorite";
String h3 = "book";
// LinkedList implementation in Java
LinkedList<string> linkedList = new LinkedList();
linkedList.add(h1);
linkedList.add(h2);
linkedList.add(h3);
System.out.println("my list after adding 3 elements:");
System.out.println(linkedList);
System.out.println("element #2 of my list:");
System.out.println(linkedList.get(2));
linkedList.remove(1);
System.out.println("my list after removing #1:");
System.out.println(linkedList);
linkedList.add(1,"first");
System.out.println("my list after adding an element in the middle");
System.out.println(linkedList);
}
运行这个程序的结果:
my list after adding 3 elements:
[my, favorite, book]
element #2 of my list:
book
my list after removing #1:
[my, book]
my list after adding an element in the middle
[my, first, book]
GO TO FULL VERSION