ArrayList如何提供随机访问行为?

时间:2015-09-24 10:22:59

标签: java arraylist

ArrayList简单地实现为Object []。我知道它实现了RandomAccess接口,但它只是一个标记接口...

所以,我的问题是:为什么/如何使用ArrayList提供随机访问功能?

编辑1:也许我应该更清楚......我想要理解的是为什么在它是Object []时访问元素的时间是恒定的?

6 个答案:

答案 0 :(得分:7)

通过直观地比较LinkedList,ArrayList和Array,可以简化:

关键列表:

+----+      +----+      +----+      +----+
|Head| ---> | e1 | ---> | e2 | ---> | e3 | ---> null
+----+      +----+      +----+      +----+

现在,假设我想获取元素e2,但是Linkedlist本身保存了headNode的引用。要到达e2,我必须从HeadNode一直遍历到e2。显然,这不提供恒定的时间操作,因为如果不遍历列表就无法直接访问任何元素。

<强>阵列:

+----++----++----++----+
| e1 || e2 || e3 || e4 |  (value)
+----++----++----++----+
| 01 || 02 || 03 || 04 |  (address)
+----++----++----++----+

想象一下,当你有一个包含数组的变量时,只有第一个元素(e1)的地址保存在变量中。以下数组元素将存储在下一个可用内存块中。数组元素在存储器中以连续顺序彼此相邻。当您需要访问特定元素时,这使其成为一个恒定的时间操作。例如,当您要访问e3时,每个内存块为4个字节。从第一个元素开始,从数组引用移动2个内存块(8个字节)。恒定时间操作的关键是:不需要遍历。它只需根据每个块的大小和要移动的块数(由数组索引表示)计算从当前位置移位的字节数。在Java中,当您尝试超出阵列的已分配内存范围时,它会为您提供ArrayIndexOutOfBoundsException

<强>的ArrayList:

Arraylist使用相同的数组概念。它最初将分配10的大小。当需要增长(例如添加更多元素)时,它会创建一个新的数组,并增加存储长度。由于数据的存储是通过数组存储的,因此操作时间将与数组相同(即恒定时间)。

答案 1 :(得分:2)

  

为什么

因为您使用ArrayList的原因之一,因为您希望对元素进行持续时间访问。因此ArrayList标记RandomAccess会告诉您它所提供的内容。如果您不需要,可以使用LinkedList代替,提供定时访问但不必偶尔进行大的重新分配ArrayList必须这样做。

  

如何

通过使用封面下的阵列。数组提供恒定时间访问,所以......

答案 2 :(得分:0)

正如你所说,RandomAccess纯粹是一个标记界面。通过将其添加到集合类,可以(基本上)指示get(int)是在恒定时间内实现的。

ArrayList这样做是因为它最终是一个从特定位置获取值的内存访问。

答案 3 :(得分:0)

根据定义,数组是随机访问数据结构。数组具有每个元素的固定偏移量。如果我想访问数组的n元素,我可以简单地访问内存地址<base offset> + n * <element size>。不需要迭代。 ArrayList是一个List - 实现,由数组内部支持,以便继承此属性。只要ArrayList的后备数组不再适合其元素,ArrayList就会将所有元素复制到一个新数组中。这就是为什么LinkedList在收集未知数量的元素时可以更有效率。为此,不能通过计算固定索引来访问元素。

RandomAccess标记接口向该列表的用户发出随机可访问性信号,以便在需要随机访问时实现高效算法。例如,LinkedList公开与ArrayList相同的界面。需要随机访问但永远不会更改列表大小的排序算法然后会在排序时将非随机可访问列表的元素复制到更有效的数据结构中。然后,它可以在单个传递中迭代非随机可访问列表,以使用已排序元素填充列表。

答案 4 :(得分:0)

ArrayList的元素可以随机访问,即您可以随时选择索引来获取列表中的元素:

myList.get(3);
myList.get(1);
myList.get(5);

ArrayList元素的get()方法实现为:

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}

要按索引访问数组中的单个元素,您需要恒定时间。无论(基于数组)列表中有多少元素,您始终可以在同一时间获取条目。元素是在列表的开头,中间还是末尾并不重要。

相反的是顺序访问,例如在LinkedList中使用,其中每个元素包含对列表中下一个项目的引用。您无法在此处随机访问元素,但您必须遍历所有先前项目才能到达目标元素:

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

此处您的访问费用取决于列表的长度和列表中的项目数。可以更快地访问列表开头的元素,因为到达它们的路径更短。访问列表中间或末尾的元素代价更高,因为您必须按顺序遍历所有其他元素。

答案 5 :(得分:0)

  

在计算机科学中,随机访问(更准确地说,更通常称为直接访问)是在可寻址群体中的任何给定坐标处访问数据项的能力。维基百科

ArrayList使用方法get(int)提供访问任何元素的API。

intObject[]中项目的索引。

此方法允许您随机访问项目(随意)。相反的是您必须在结构项中移动的顺序访问(LinkedList)。