java数组插入速度_关于优化:添加元素时,java链表比数组表慢?

我以为链表在添加元素时应该比数组表更快? 我只是测试了添加,排序和搜索元素(数组列表,链表和哈希集)需要多长时间。 我只是对数组列表和链接列表使用java.util类...使用每个类都可以使用的两个add(object)方法。

arraylist在填充列表中执行链表...并线性搜索列表。

这是正确的吗? 我在执行中做错了吗?

***************编辑*****************

我只想确保我正确使用了这些东西。 这是我在做什么:

public class LinkedListTest {

private List Names;

public LinkedListTest(){

Names = new LinkedList();

}

然后,我只使用链表方法,即" Names.add(strings)"。 当我测试数组列表时,几乎是相同的:

public class ArrayListTest {

private List Names;

public ArrayListTest(){

Names = new ArrayList();

}

我做对了吗?

这取决于...您的测试代码是什么样的? 如果将ArrayList初始化为已知大小,则ArrayList可能会更快。 LinkedList带有一些额外的开销,因为每个元素必须包装在一个节点中,以便它可以包含对prev和next的引用。 达到现有容量并将所有元素复制到新阵列时,初始化一个全新的后备阵列会导致ArrayList性能问题。

@Mark-不,不将arraylist初始化为已知大小。

是的,这是正确的。 LinkedList将必须在每次插入时进行内存分配,而ArrayList则可以进行较少的分配,从而将其摊销为O(1)插入。内存分配看起来很便宜,但实际上可能非常昂贵。

由于参考位置的限制,LinkedList中的线性搜索时间可能会更慢:ArrayList元素靠得更近,因此较少的缓存未命中。

当您计划仅在List的末尾插入时,ArrayList是您选择的实现。

好的,我想这很有道理。我做了一些谷歌搜索...一些网站说,添加到链表的末尾或开始应该比对arraylist进行速度更快。为什么?我还阅读了一个站点,该站点表示链表和数组列表的add()方法的时间复杂度均为O(1)。什么?真?!?!

@user:ArrayList的追加(末尾插入)时间摊销为O(1),这意味着在执行较长的追加序列时,其平均O(1)。它们中的任何一个都可以是O(n),但容量要增加一倍,因此下一个n可以使用预分配的空间。

@larsmans,缓存缺失是阵列备份结构的主要卖点。链接结构可能是每个节点上的高速缓存未命中,这使得O(n)迭代实际上显着变慢。

@bestsss:我的意思是LinkedList会导致许多缓存未命中。为了清晰起见,编辑了我的答案。

即使链表根本不包含任何高速缓存未命中,遍历也会变慢。这是因为访问每个项目会导致两次取消引用操作的开销,而不是数组列表所需的单个取消引用操作的开销。

事实证明,使用一系列对象引用创建数组,并且对象本身驻留在内存的无关部分中。如果您有对象数组而不是基元数组,则它与链接列表一样容易受到缓存丢失的影响。

@larsmans,我的评论丝毫没有受到批评,我很高兴有人(除我以外)提到使用Java结构时缓存未命中。主要是赞美。

@Zoe,缓存行相对较短-x86上为64字节。因此,具有8个字节的参考大小,它在ArrayList的缓存未命中后会命中7个缓存。使用LinkedList,您可以假设每个元素上的缓存未命中(当然这不是必须的,但这只是一个猜测)。与任何其他操作相比,高速缓存未命中太慢了(可能慢100倍)。

请记住:

对于给定数量的元素,"原始"性能以及不同结构的缩放比例有所不同;

不同的结构在不同的操作下表现不同,这实际上是选择使用哪种结构时需要考虑的部分。

因此,例如,链表在添加末尾时还有更多工作要做,因为它有一个附加的对象来分配和初始化添加的每个项目,但是无论每个项目的"内在"成本如何,两个结构都将具有O(1)添加到列表末尾的性能,即无论列表大小如何,每次添加都具有有效的"恒定"时间,但是ArrayList与LinkedList之间的常数将有所不同,后者可能更大。

另一方面,链表具有恒定的时间来添加到列表的开头,而在ArrayList的情况下,必须对元素进行"装卸",该操作所花费的时间与元素的数量成正比。但是,对于给定的列表大小(例如100个元素),"笨拙" 100个元素可能比分配和初始化链表的单个占位符对象要快(但是到您说的时候,一千个或一百万个对象或任何阈值,它将不会)。

因此,在测试中,您可能既要考虑给定大小的操作的"原始"时间,又要考虑这些操作如何随着列表大小的增长而扩展。

在某些情况下,链接列表可能比数组列表慢。如果要插入列表的末尾,则很可能阵列列表已分配了该空间。底层数组通常会大量增加,因为这是一个非常耗时的过程。因此,在大多数情况下,只需在后面添加元素即可,而在链表中则需要创建一个节点。对于这两种类型的列表,在前面和中间添加都应具有不同的性能。

在基于数组的列表中,列表的线性遍历总是更快,因为它只能正常地遍历数组。这要求每个单元进行一次解引用操作。在链接列表中,还必须取消引用列表的节点,这要花费两倍的时间。

您为什么认为LinkedList会更快?在一般情况下,插入到数组列表中只是在更新单个数组单元的指针(使用O(1)随机访问)的情况。 LinkedList插入也是随机访问,但必须分配一个"单元"对象来保存该条目,并更新一对指针,并最终设置对要插入的对象的引用。

当然,可能需要定期调整ArrayList的后备数组的大小(如果选择具有足够大的初始容量的情况就不会如此),但是由于该数组呈指数增长,因此摊销成本会很低,并且受其限制O(lg n)复杂度。

简而言之-插入数组列表要简单得多,因此总体上要快得多。

好吧,如果我们定义"插入"是在集合中的任意位置添加元素(这是默认定义),则您必须将所有元素移动到该位置之后。 Id关于有缺陷的基准的第一个提示。

将元素添加到LinkedList的后面时(在Java中,LinkedList实际上是一个双链表),它是O(1)操作,就像将元素添加到它的前面一样。在第i个位置上添加元素大约是一个O(i)操作。

因此,如果您要添加到列表的最前面,则LinkedList会明显更快。

实际上,Arent Java LinkedLists是双重链接的-我认为添加到哪一端并不重要。

啊,我不知道实现细节,但这可能是正确的。我会仔细研究它,并在必要时删除我的答案。

似乎LinkedList确实是一个双重链接列表,很有趣。

@Argote-这样是否会使添加到链表两端的速度比添加到arraylist慢还是快?

好吧,在链表上开始添加应该更快,而在数组列表的末尾添加应该稍微快一点。

@Argote-不。香港专业教育学院现在都尝试。无论哪种方式,链表都比数组表慢。您能看一下我上面的代码片段,并确保我没有做错什么吗?

好吧,正如其他人提到的那样,这也取决于每个列表中的数据量。 LinkedList具有较高的开销,一旦需要在ArrayList上重定位的元素数量超过某个阈值,就可能会抵消这些开销。

ArrayList在访问随机索引数据时速度更快,但是在列表中间插入元素时速度较慢,因为使用链接列表只需要更改参考值即可。但是,在数组列表中,您必须将所有元素复制到插入的索引之后,后面是一个索引。

编辑:没有一个链接表实现记住最后一个元素吗?这样可以加快使用链表最后插入的速度。

实际上,您也不能随机插入LinkedList中,以便找到插入点,这是必需的。

保留对最后一个元素的引用会导致从O(n)到O(1)的追加,但在进行大量追加时仍不会击败动态数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值