ArrayList和LinkedList的区别和使用场景

要看这两个类的区别,我们需要先看它们是怎么实现的。这里我来简述他们的实现原理。

首先,它们都继承了list(表)这个接口,表是三大抽象数据类型之一,这两个类都是对表进行操作。然后表这个接口里定义了它们必须要实现的方法,比如add(E),get(int),remove(int),set(E)等基本的表操作,然后这两个类就按照它们自己的方法来实现这些表的基本操作。

ArrayList的实现原理及其注意地方:首先,它是由一个数组组成最基本的结构,然后,它与数组的区别是它可以改变数组的大小。比如说,我们创建数组时就定了它的大小,只有get和set等方法,没有add方法,然后如果要add方法,则要新建一个比较大的数组,然后有一个复制短数组到长数组里面的方法,把原来的数组放到新的数组里面。至于要新建多大的数组,我没有仔细研究过,我写的时候直接取1.5倍原来数组容量的大小(但其实这样是不太科学的,因为如果增加的数量很多,那你这可能要多扩容几次,这就影响了程序运行的效率,如果就这增加一个元素,那么就可能扩容过多,浪费空间),然后其他的方法都是基本操作了。

LinkedList的实现原理及其注意地方:它其实就是一个双向链表,写好结点类,理解链表的意思即可。

ArrayList的优点是对get和set方法的调用花费常数时间,缺点是新项的插入和现有项的删除比较耗费时间和空间,因为本质上来说它要移动数据。而LinkedList恰恰相反,它的优点在于新项的插入和现有项的删除开销很小,由链表的原理即可知道,比如说现有项的删除,把前一个节点.的.指向下一个节点的属性.改到指向它的后一个节点即可。具体操作可看网上简单基础教程。但是它的get就很费时间了,因为它必须从头到尾去找到那个位置先,就是移动指针,不能想数组那样一下子就跳到该位置上。

所以,根据它们的优缺点,可以知道,ArrayList适用于频繁查询和获取数据,比如说一个图书馆的数据库的数据的存储,它日常生活中都是看看书在哪里,或者书的作者等其它属性,而不用每天都要增加新的书或者把旧书丢掉。LinkedList适合频繁地增加或删除数据,比如如果你要做最近十年的流行手机的存储,那么它的更新就很快,手机淘汰很快,新的流行手机的出现也很快。这个时候你就需要LinkedList了。

建议可以看看网上的自己手写的这两个类的实现,比jdk源码的简单多了,但思想差不多。

这里受到一位网友的启发,决定把一些基础的东西再来分享一下。

在这里补充一下,因为它(arraylist)是数组的基础结构,所以它的查找比较快,比如说在数组中我们要得到a[5],那么我们是用a[0]的地址加上4乘以每个数组元素的字节长度。所以这里需要的时间是常数时间。所以查找比较快。而插入和删除则如我所说的那样,插入要增加数组的长度,所以要新建一个数组来存放原来的数组加上新插入的元素,即移动数据。删除一个元素也是类似。而关于linkedlist,它的插入和删除比较快是因为链表的基本特性,比如有1,2,3三个节点,如果要删除第二个节点,则只需要第一个节点的属性:指向下一个节点的属性,指向第三个节点(原来是指向第二个节点)即可,然后第二个节点就会自动被jvm视为垃圾,等到cpu的回收垃圾的线程到了相应的时刻就会把第二个节点当做垃圾清理掉。这就是链表删除节点。而插入也是类似的原理,我就不废话了。而关于查找,则根据链表的组成原理,要获取单向链表的某个元素,则必须从头节点开始,进行一次遍历,依次判断是否等于自己要查找的元素的值。知道找到为止。所以这里的查找可以说要O(n)的时间(关于时空间的复杂度,我先用我之前接触的为标准)。所以查找的话效率比较低。

有网友问到为啥linkedlist要用双向链表而不用单链表,这里再来啰嗦一下:直接看源码,定位了一下它的get(int)函数,然后最终看到node(int)函数。然后我还是先普及一下基础知识,也不知道大家懂不懂,双向链表比起单链表来,从结构上看,就是双向链表的节点类要多一个属性,就是指向前一个节点的属性,在c中就叫指针。这样就很有效率地实现双向遍历。然后回到前面说的node(int)函数,它通过判断索引在整个链表的位置,然后选择是从第一个节点往后遍历,还是从最后一个节点往前遍历,这样,它的遍历时间就减少了一半,而单链表的话只能从头遍历到尾部。这样看的话双向链表的时间空间的效率就高了。然后,再综合来看,由于它的节点类增加了指向前一个节点的属性,操作起数据来更加灵活,建议大家看一下源代码。然后就是由于增加了这个属性,所以它的增加和删除就稍微复杂了一点点,毕竟要指定它的指向前一个节点的属性指向哪里嘛,不过这不碍事,影响不大。

另外,如果大家有什么不懂的地方欢迎在评论区提问,只要有问题我就肯定会竭尽所能回答。我也不知道大家的基础怎么样,所以有些东西可能考虑的不周到。所以,沟通交流才是解决问题的最好方法。谢谢

------小更新----

1.注意,由于arraylist中删除元素是会改变长度的,所以遍历比较的时候要注意,当你删除一个元素后,后面的元素全部前移,所以,如果要进行比较你还需要从原来的位置再进行比较,不然会由于你指针的后移导致你忽略了刚刚前移上来的元素。你们可以试试删除对象中重复的元素,然后思考一下就知道咋回事了。

2.vector是同步的,其它的都和arraylist差不多,我们打开它的源码就可以看到基本上操作了这个数组结构的方法都加上了synchronized修饰,表面操作的时候都需要先获取锁this,然后才能操作。所以效率比较低。而arraylist和linkedlist都是不同步的,要使它同步可以在创建的时候用其他方法创建,具体可见API文档。然后在实际开发当中,我们存数据一般都是为了查询,所以我们一般都用arraylist。然后注意一下linkedlist用来构造队列,堆栈很方便,因为它操作最前面和最后面的指针和元素很方便,所以构建先进先出或者后进先出都是soeasy的。可以尝试一下。

猜你喜欢

转载自blog.csdn.net/feelinghappy/article/details/84402373