什么是对(慢)访问链接列表的内部元素的资格

时间:2011-04-30 19:23:56

标签: java collections arraylist

LinkedList上的帖子说:

LinkedList允许恒定时间插入或删除,但只允许顺序访问元素。换句话说,you can walk the list forwards or backwards, but grabbing an element in the middle需要的时间与列表的大小成正比。

我不明白什么才有资格抓住中间的元素?

在下面的代码中,假设arrL是一个包含50个elemnet的LinkedList,当计数器j达到20时,程序执行arrL.get(20) ..这是否意味着程序正在抓取中间元素?同样在下面的程序中,我只是向前走,不是吗?

    for(int j=0;j<arrL.size();++j){
        arrL.get(j);
    }

4 个答案:

答案 0 :(得分:8)

是的,在每次迭代中,您从头到尾遍历第j 个元素,因此整体循环性能为n^2(非常差)。这是因为在每次迭代中,您都有独立的get()调用,它具有线性性能。

另一方面,如果使用迭代器,您将一次遍历列表一个元素,在每次迭代中前进一个元素,这要快得多:

for(Iterator<E> iter = arrL.iterator(); iter.hasNext();) {
  E e = iter.next();
}

或更好:

for(E k: arrL) {
}

BTW这是一个非常的基本数据结构问题,Java在这里无关......

答案 1 :(得分:1)

对于LinkedList,get(N)需要与N成比例的时间。所以 - get(19)大约是get(0)的20倍。上面的for循环在O(n ^ 2)时间内运行 - n遍,每次通过O(n)时间。如果要按顺序访问成员,请使用迭代器:

Iterator it = arrL.iterator();
while(it.hasNext()) {
   it.next();
}

或暗示,如此:

for(Obj o : arrL) {
  // do something with o
}

答案 2 :(得分:0)

在链表中,每个列表条目只知道其前任及其后继:它们只是相互链接。关于这一点的好处是,只需添加和链接到新元素就可以轻松地使这个列表增长。但是到达列表中不是端点的元素需要从任一端走到特定元素。因此,每次调用get(j)都需要从链/列表中的端点进行j元素访问。换句话说,get(j)在时间上相当昂贵。例如,如果列表包含1000个元素,则获取元素编号500需要从任一端进行500次访问。如果列表长度为2000个元素,那么到中间元素(元素1000)同样需要1000次访问,因为我们遵循节点链接(链)。

相反,访问数组中的任何元素都需要一段时间。

答案 3 :(得分:0)

@Vicky,这意味着每次调用arraL.get(j)时,此操作都需要线性时间才能执行。这意味着当你获得第20个元素时,它将从头开始(或结束,我不确定实现)并将整个列表横向扩展到第20个元素。 另一个实现ArrayList将在恒定时间内执行此操作(内部保留数组,因此您可以将arrL.get(20)视为array[20]),但每次删除中间的项目时,它必须移动数组中的元素。 所以基本上,对于随机读取,ArrayList是一个更好的选择,性能明智,当你执行大量删除时,LinkedList是更好的选择。