CodeGym /Java 博客 /随机的 /Java 双端队列接口
John Squirrels
第 41 级
San Francisco

Java 双端队列接口

已在 随机的 群组中发布
Java Deque是一种结合了普通Queue和Stack的数据结构。您可以在 Deque 的头部和尾部添加和删除元素。在“传统”队列中,您将元素添加到行的尾部(在最后一个元素之后)并从队列的头部移除元素。这一原则称为先进先出 (FIFO),它的工作方式与现实生活中任何常见的客户排队一样。在 Java 中,队列是一个接口,是集合框架的一部分。 Java 双端队列接口 - 1 还有一个重要的数据结构称为 Stack,这是一个以完全相反的原则处理元素的列表,LIFO——后进先出。它类似于一堆盘子,只能在顶部添加或移除。 Java 双端队列接口 - 2

队列与双端队列

Deque 是一种奇怪的队列类型:您可以将新元素添加到行的尾部和头部。删除的情况相同:您可以从此结构中删除最后一个或第一个元素。因此,它似乎是 Stack 和 Queue 的混合体。 Java 双端队列接口 - 3“Deque”这个名字的意思是“双端队列”。“Deque”的发音就像一副纸牌,你知道吗?它有点类似于一副真正的纸牌:你可以从这样一副纸牌的底部或顶部拿一张牌。想在某些线性结构的两侧添加或删除元素?使用双端队列。Java 8 或几乎任何其他版本都支持它。想象一下典型的乐高积木和由积木制成的单柱“塔”。您可以在塔的顶部或底部添加一块新砖。您也可以从两侧移除一块砖。这里有一个示例:我们将所有黄色积木添加到顶部,将所有红色积木添加到底部。我们将很快用 Java 代码演示这个例子。 Java 双端队列接口 - 4因此,您可以从 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 接口定义了一些方法,使您能够执行典型的堆栈操作,例如pushpeekpop
  • 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。
在下表中,所有方法都按组划分。如您所见,有许多不同的方法可以添加和删除元素。例如,removeFirst() 和 pop() 都从双端队列中删除第一个元素。第二个来自堆栈。这意味着如果您仅将 ArrayDeque 用作堆栈,请使用 pop() 删除,使用 push() 添加并使用 peek() 检查。这使您的代码对其他开发人员更明智。
第一元素(头) 最后一个元素(尾巴)
手术 抛出异常 特别价值 抛出异常 特别价值
插入 添加第一(e)/推(e) 报价第一(e) 添加最后一个(e) 最后报价()
消除 removeFirst()/弹出() 轮询优先() 移除最后一个() 轮询最后()
检查 getFirst() peekFirst()/偷看() 获取最后一个() peekLast()

双端队列实现

Java Deque 是一个接口,在 Java Collections API 中有实现:
  • java.util.LinkedList //List和Deque的实现
  • java.util.ArrayDeque //双端队列实现,Java库
Java 双端队列接口 - 5LinkedList 类在内部使用双链表来模拟队列或双端队列。ArrayDeque 类将元素内部存储在数组中。如果元素的数量超过数组的体积,则分配一个新数组,并将所有元素移过去。这意味着 ArrayDeque 根据需要增长。

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 是一个双向队列,它支持从两侧添加和删除元素。 Java 双端队列接口 - 6LinkedList 主要被称为 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]
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION