ArrayDeque操作

问题描述

我有一些空闲时间,试图了解arraydeque在内部如何工作。我在这里阅读了几篇文章和问题/答案,我想我已经很接近了。我使用调试来遵循工作流程,这让我很困扰。 我创建了一个空的双端队列,结果是一个包含16个为空的元素的数组。 当我使用 addFirst 时,它在数组中的位置16处添加一个元素,并在位置0的开头处添加 addLast 。我想念的是什么,请您分享一些知识或为我指明正确的方向,这样我就可以完全理解幕后发生的事情。 提前谢谢!

解决方法

基于数组的双端队列通常使用称为 循环缓冲区 的数据结构实现。这个想法是我们维护一个元素数组,但假装该数组的末端粘合在一起形成一个环。

通过调试,看来ArrayDeque内部维护着一个由16个元素组成的数组,我们可以这样查看:

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

我们维护两个不同的指针,一个 head指针和一个 tail指针,跟踪双端队列的第一个元素的位置和最后一个元素的位置双端队列的元素。最初,它们将指向数组的开头:

 head
  |
  v
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  ^
  |
 tail

每当执行addFirst时,我们都会将头指针备份一步,然后将元素写入找到的位置。由于我们假装数组的两端已链接在一起,因此在此处备份一个步骤会将头指针移动到最后一个位置:

                                                             head
                                                              |
                                                              v
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   | X |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  ^
  |
 tail

要做一个addLast,我们写到尾部位置,然后向前推进:

                                                             head
                                                              |
                                                              v
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| X |   |   |   |   |   |   |   |   |   |   |   |   |   |   | X |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      ^
      |
     tail

如果再执行两次addFirst,就会是这样:

                                                     head
                                                      |
                                                      v
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| X |   |   |   |   |   |   |   |   |   |   |   |   | X | X | X |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      ^
      |
     tail

如果再执行两次addLast,结果将是这样:

                                                     head
                                                      |
                                                      v
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| X | X | X |   |   |   |   |   |   |   |   |   |   | X | X | X |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
              ^
              |
             tail

我们从头指针开始并向前前进直到到达尾指针,从而读取了双端队列的元素。因此,在这种情况下,我们从head所指向的插槽开始读取,而不是从数组的第一个位置开始读取。

最终,两个指针将在中间相遇。发生这种情况时,我们将创建一个比原始数组大(通常大150%)的全新数组,然后将元素复制到新数组中以释放一些空间。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...