ArrayList 与LinkedList 源码分析,效率比较

ArrayList 与LinkedList 源码分析,比较

ArrayList , LinkedList都是 List接口的实现类, ArrayList 底层是一个Object数组, LinkedList是一个双向链表,他们都是线程不安全的

ArrayList

先看看变量吧:
elementData : ArrayList数据的存放位置, 一目了然,是一个Object数组, 修饰符 transtient 的作用是使得该变量不能再被序列化
ArrayList 与LinkedList 源码分析,效率比较_第1张图片
DEFAULT_CAPACITY : ArrayList的默认容量,初始化时若没有显示指定容量, 默认为 10 , 在 ensureCapacityInternal 方法中设置默认容量
ArrayList 与LinkedList 源码分析,效率比较_第2张图片
size : 当前该ArrayList的大小, 实际存储的数据量,注意与ellmentData数组的长度区别 , 是不一样的
ArrayList 与LinkedList 源码分析,效率比较_第3张图片
modCount : 这是ArrayList的 父类AbstractList类中定义的变量,表示结构修改的次数, 当并发时, 若modCount不一致,触发快速失败

然后我们知道,java数组创建之后长度是固定的, 一直往数组里添加元素,数组下标会越界,这就需要对数组进行扩容

扩容时机: list的容量(Object数组的长度 ) < 需要存储的数据量。
下图代码中, minCapacity 指的是当前需要存储的数据量(size + 1),
ArrayList 与LinkedList 源码分析,效率比较_第4张图片
扩容大小: 1.5倍, 如果新的数组大小大于 该ArrayList最大容量时,就更新为 MAX_ARRAY_SIZE。 下图关键代码 :
newCapacity = oldCapacity + (oldCapacity >> 1) , >> : 位运算,往右移动一位,
ArrayList 与LinkedList 源码分析,效率比较_第5张图片
扩容方法: Arrays.copyOf() , 重新申请内存,再赋值给elementData,该方法使用 System类的arraycopy() (这是一个native方法)移动数据, 操作内存,整体移动数据,效率高,包括插入,删除操作的移动数据也是使用该arraycopy方法

LinkedList

底层是一个双向链表,节点 结构如下:next 指向下一个节点, prev指向前一个,
ArrayList 与LinkedList 源码分析,效率比较_第6张图片
维护了两个引用,first 指向链表的第一个节点, last指向最后一个, 因为是链表 ,所以不存在扩容,直接插入即可ArrayList 与LinkedList 源码分析,效率比较_第7张图片
node(int index) 判断 index 靠近左边还是右边从更近的地方开始移动

ArrayList, LinkedList 查询效率比较:
ArrayList 是 Object数组实现的,可以直接通过下标随机查找, 时间复杂度 是O(1),
LinkedList 底层是双向链表, LinkedList 需要从 头或尾节点 移动到指定的节点,时间复杂度为 O (n), 所以 ArrayList的查询效率高
插入,删除效率比较:
具体需要分情况讨论:
(请注意,这里的效率比较,都默认数据量很大的情况)

操作尾部, ArrayList, LinkedList 效率差不多,都可以直接插入

操作首部,LinkedList 效率高 ,可以直接插入,主要时间开销是,生成节点的时间, ArrayList (Object数组)需要移动操作位置后的元素,扩容也需要时间

操作非首尾部元素时, ArrayList效率高 , 因为 ArrayList 虽然需要移动数据,但,使用的是 System.arraycopy() (native方法)操作内存,整体移动,效率高, LinkedList 需要从 头或尾节点 移动到指定的节点再操作,效率低, 并且数据量越大,差距越明显

你可能感兴趣的:(java,数据结构)