Java集合方面的面试题:ArrayList和LinkedList有什么差别?分别适用于哪些场景?

List是封装了针对线性表操作的接口,ArrayList和LinkedList是在项目里用的比较多的两个实现类。我在面试时一般会问,它们两者有什么差别?很多人能回答说,ArrayList是基于数组实现,而LinkedList是基于双向链表实现。

学过数据结构的同学都知道,如果我们要查找数组里的某个元素,可以根据如下的公式很快地定位到该元素的位置。

第i号元素的位置 = 第0号元素的位置+(i-1)*每个元素的长度。

但数组不擅长添加和删除元素,比如要在长度是10000的数组里的500号位置添加一个元素,我们首先得让500到10000号元素都往后移动一位,先把500号位置腾出来,随后再添加。删除也是类似。

和数组相对应,链表比较擅长添加和删除元素(只需要更改其中一个元素的指针即可),但不擅长于定位(如果要找500号元素,就得从0号开始一个个找)。

这种说法应付面试尚可,但在实际项目里,往往没有单纯的添加(或删除)和单纯的查找操作,一般是两者配合使用。比如我们会在一个for循环里通过add方法从头开始在尾部添加元素,完成后在另个地方通过get方法从头开始获取元素,这两个动作往往会配对出现

那么在这种情况下,该选用哪种集合?下面我们来通过ListCompare.java来比较一下这两类List的各种性能,从而来归纳它们的使用场景。

1	//省略必要的import集合包的代码
2	public class ListCompare {	
3	//在尾部添加元素 
4		static void testAddatTail(List list,String type)	{
5			int size = 1000000;		
6			long start=System.currentTimeMillis();  		
7	     //通过for循环在尾部添加元数据
8			for(int i = 0;i<size;i++)
9			{list.add(i);}
10			long end=System.currentTimeMillis();
11			System.out.println("testAddatTail for " + type);
12	     //结束时间减开始时间就是运行时间
13			System.out.println(end - start);
14		}
15		//随机查找元素
16		static void testRandomSearch(List list,String type)	{
17			Random rand = new Random();        
18			long start=System.currentTimeMillis();  
19			//在for循环里随机查找元素
20			for(int i = 0;i<10000;i++)
21	  	{list.indexOf(rand.nextInt(100000));}
22			long end=System.currentTimeMillis();
23			System.out.println("testRandomSearch for " + type);
24			System.out.println(end - start);
25		}	
26	//随机地添加元素
27		static void testAddatRandom(List list,String type){
28			Random rand = new Random();		
29			long start=System.currentTimeMillis();  
30			for(int i = 0;i<1000;i++)
31	    {list.add(rand.nextInt(100000), "0");}
32			long end=System.currentTimeMillis();
33			System.out.println("testAddatRandom for " + type);
34			System.out.println(end - start);
35		}
36		//主方法
37		public static void main(String[] args) {
38	     //创建两种不同类型的List						
39			List arrayList = new ArrayList();
40			List linkedList = new LinkedList(); 
41			//如下是对比实现
42			testAddatTail(arrayList,"ArrayList");
43			testAddatTail(linkedList,"LinketList");		
44			testAddatRandom(arrayList,"ArrayList");
45			testAddatRandom(linkedList,"LinketList");		
46			testRandomSearch(arrayList,"ArrayList");
47			testRandomSearch(linkedList,"LinketList");
48		}
49	}

在下表3.1里,我们列出了在上述代码里定义的方法。

表3.1 针对两种不同集合对比测试方法归纳表

方法名

行数

动作

testAddatTail

第4到14行

通过for循环在尾部添加1000000个元素

testRandomSearch

第16到25行

从集合的随机位置拿元素,相当于随机查找

testAddatRandom

第27到35行

在集合的随机位置添加元素

在main函数的39和40行,我们定义了两种List,随后从42到47行,我们分别针对两种不同的List集合执行了对比测试方法,如果我们运行多次,输出的时间未必都相等,但从中我们能看到两者的对比,根据其中的一次运行结果,我们能整理出如下表3.2所示的结论。

表3.2 运行结果分析表

比较项

集合种类

运行时间

分析

在尾部添加

ArrayList

141

ArrayList是基于数组,和基于链表的ListedList相比,能很快地定位到尾部

LinkedList

219

在随机位置添加

ArrayList

938

这里包含查找位置和添加两个动作,查找时基于数组的ArrayList占优,添加时基于LinkedList占优,综合下来还是LinkedList占优

LinkedList

672

在随机位置查找

ArrayList

4109

基于数组的ArrayList很占优,相比基于链表的Linkedlist就需要消耗一定的代价了。

LinkedList

5828

也就是说,如果被问到这类问题,你可以说出如下的结论。

第一,如果我们就一次性地通过add从集合尾部添加元素,添加完成后我们也只需读取一次,那么建议使用ArrayList,因为从上表来看,它两个动作的运行时间总和要小于LinketList。

第二,如果要频繁地添加元素,或者在完成添加元素后会频繁地通过indexOf方法从集合里查找元素,可以使用LinketList,理由是它的随机添加和随机查找的总时间消耗要小于ArrayList。

第三,请记得,如果在代码里indexOf的操作过于频繁从而成为项目运行的瓶颈时,可以考虑后文里提到的HashMap对象。

此外,ArrayList和Linkedlist都是线程不安全的,别把这点说成是它们的差别。

  关于集合类的面试文章汇总:

Java集合方面的面试题:Set集合是如何判断重复

Java集合方面的面试题:对比ArrayList和Vector对象,分析Vector为什么不常用
Java集合方面的面试题:ArrayList和LinkedList有什么差别?分别适用于哪些场景?
Java集合方面的面试题:TreeSet、HashSet和LinkedHashSet的各自特点

Java集合方面的面试题:泛型的继承和通配符

Java集合方面的面试题大汇总

 这是我的公众号,其中包含了大量面试文章,同时我自己出了多本Python和Java方面的书籍,会定期在公众号里发书的电子版。请大家关注下我的公众号,谢谢了。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hsm_computer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值