LinkedList和ArrayList异同


ArrayList与LinkedList的异同是我面试较常问的问题。大部分人可能都知道前者基于数组而后者基于链表(能答出双向链表自然更好),并且前者适合读取、后者适合插入删除;偶有候选人能曰“It depends”并给出具体情况之分析时,往往能获得不错的第一印象。 

抛开具体语言的实现不说,先从数据结构上看一下,两者时间、空间负责度上的区别: 



查找自不必说,插入删除与具体的位置有关,如果在首部、中部执行增删,考虑到ArrayList需要复制指定位置之后的所有元素,因此具有O(N)的时间复杂度;而LinkedList则只需O(1)。 

如果是尾部增加、删除的情况,ArrayList不需要移动任何元素,因此两者的理论时间复杂度都为 
O(1)。考虑得更细一点,如果是尾部增加的情况,LinkedList需要重新向JVM申请内存空间,而ArrayList不需要,因其一开始就会申请较多的空间,并且可以通过初始化capacity来避免动态膨胀的开销;如果是尾部减少的情况,LinkedList或许会带来GC释放内存的开销,而ArrayList仅需简单的将length减一;并且考虑到今后的扩展性,无论是哪种情况,使用ArrayList要划算得多。 

另外,特别提一下删除操作,我前面特意强调“抛开具体语言不说”,是因为虽然理论上LinkedList的随机增删的时间复杂度是O(1),但那是对于传入的是其内部某节点指针或者entry而言的,而事实上,在JAVA中由于不存在指针一说,并且对其数据结构的完美隐藏,大部分情况我们不会直接传入某个entry,而是基于以下两种情况的元素删除: 


删除特定index的元素,对应LinkedList.remove(int)方法 
删除特定值的元素,LinkedList.remove(Object) 


事实上,对于上述情况,在删除前势必需要一个定位查找的工作,而众所周知,LinkedList在元素遍历上相当低效的,因此删除元素的时间复杂度应该是O(1) + O(N),也就是O(N)。当然java进行了优化,譬如说采用折半查找索引的方式 

Entry<E> e = header;    
if (index < (size >> 1)) {    
//looking forward   
for (int i = 0; i <= index; i++)    
    e = e.next;    
} else {    
//looking backward   
for (int i = size; i > index; i–)    
    e = e.previous;    
}  

Entry<E> e = header; 
if (index < (size >> 1)) { 
//looking forward
for (int i = 0; i <= index; i++) 
    e = e.next; 
} else { 
//looking backward
for (int i = size; i > index; i–) 
    e = e.previous; 
}
对于LinkedList.remove(int)方法来说,LinkedList定位慢而删除快,ArrayList定位快而删除慢,因此具体谁领风骚还真不好说,不仅与具体操作的位置有关,还与集合中元素的数量有关。 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值